diff --git a/src/libmngr_frame.cpp b/src/libmngr_frame.cpp index 6a7f60b..1c2a7e3 100644 --- a/src/libmngr_frame.cpp +++ b/src/libmngr_frame.cpp @@ -9,7 +9,7 @@ * use this file except in compliance with the License. You may obtain a copy * of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT @@ -17,7 +17,7 @@ * License for the specific language governing permissions and limitations * under the License. * - * $Id: libmngr_frame.cpp 5685 2017-05-23 10:35:40Z thiadmer $ + * $Id: libmngr_frame.cpp 5686 2017-05-24 13:56:46Z thiadmer $ */ #include "librarymanager.h" #include "libmngr_frame.h" @@ -32,8 +32,8 @@ #include "rpn.h" #include "svnrev.h" #if !defined NO_CURL - #include "libmngr_dlgremotelink.h" - #include "remotelink.h" + #include "libmngr_dlgremotelink.h" + #include "remotelink.h" #endif #if !defined NO_3DMODEL #include "vrmlsupport.h" @@ -65,211 +65,211 @@ extern "C" { #if !defined M_PI - #define M_PI 3.14159265358979323846 + #define M_PI 3.14159265358979323846 #endif #if !defined sizearray - #define sizearray(a) (sizeof(a) / sizeof((a)[0])) + #define sizearray(a) (sizeof(a) / sizeof((a)[0])) #endif -#define LINE_OFFSET 5 /* in pixels (offset of the dimension line from the centre of the pad) */ -#define MEASURE_GAP 2 /* factor of the font size (the font for the dimensions) */ -#define SCALE_MIN 0.8 +#define LINE_OFFSET 5 /* in pixels (offset of the dimension line from the centre of the pad) */ +#define MEASURE_GAP 2 /* factor of the font size (the font for the dimensions) */ +#define SCALE_MIN 0.8 #define SCALE_DEFAULT 8 -#define SCALE_MAX 80 +#define SCALE_MAX 80 #if defined _WIN32 - #define PANEL_WIDTH 200 /* default width of the sidebar, in pixels */ - #define EDITF_WIDTH 150 + #define PANEL_WIDTH 200 /* default width of the sidebar, in pixels */ + #define EDITF_WIDTH 150 #else - #define PANEL_WIDTH 250 - #define EDITF_WIDTH 175 + #define PANEL_WIDTH 250 + #define EDITF_WIDTH 175 #endif -#define IMG_WIDTH_FP 128 +#define IMG_WIDTH_FP 128 #define IMG_HEIGHT_FP 128 -#define IMG_SCALE_FP 96 +#define IMG_SCALE_FP 96 #define IMG_WIDTH_SYM 160 #define IMG_HEIGHT_SYM 160 #define IMG_SCALE_SYM 450 -#define LEFTPANEL -1 -#define RIGHTPANEL 1 -#define BOTHPANELS 0 +#define LEFTPANEL -1 +#define RIGHTPANEL 1 +#define BOTHPANELS 0 #define PROTECTED wxColour(224,224,224) -#define ENABLED *wxWHITE -#define CHANGED wxColour(255,192,192) +#define ENABLED *wxWHITE +#define CHANGED wxColour(255,192,192) libmngrFrame::libmngrFrame(wxWindow* parent) : AppFrame(parent) { - #if defined _MSC_VER - _CrtCheckMemory(); - #endif - - SetIcon(wxIcon(logo32_xpm)); - - /* I prefer the flat look, but that does not look right on GTK; so it is - set only on Windows */ - #if defined _WIN32 - m_btnMove->SetWindowStyle(m_btnMove->GetWindowStyle() | wxBORDER_NONE); - m_btnCopy->SetWindowStyle(m_btnCopy->GetWindowStyle() | wxBORDER_NONE); - m_btnDelete->SetWindowStyle(m_btnDelete->GetWindowStyle() | wxBORDER_NONE); - m_btnRename->SetWindowStyle(m_btnRename->GetWindowStyle() | wxBORDER_NONE); - m_btnDuplicate->SetWindowStyle(m_btnDuplicate->GetWindowStyle() | wxBORDER_NONE); - m_btnSavePart->SetWindowStyle(m_btnSavePart->GetWindowStyle() | wxBORDER_NONE); - m_btnRevertPart->SetWindowStyle(m_btnRevertPart->GetWindowStyle() | wxBORDER_NONE); - #endif - - wxAcceleratorEntry entries[9]; - entries[0].Set(wxACCEL_CTRL, '+', IDT_ZOOMIN); // Ctrl-+ - entries[1].Set(wxACCEL_CTRL, '=', IDT_ZOOMIN); // On US keyboards, Ctrl-= is needed instead of Ctrl-+ - entries[2].Set(wxACCEL_CTRL, WXK_NUMPAD_ADD, IDT_ZOOMIN); - entries[3].Set(wxACCEL_CTRL, '-', IDT_ZOOMOUT); - entries[4].Set(wxACCEL_CTRL, WXK_NUMPAD_SUBTRACT, IDT_ZOOMOUT); - entries[5].Set(wxACCEL_CTRL, 'S', IDT_SAVE); - entries[6].Set(wxACCEL_CTRL, 'Z', IDT_REVERT); - entries[7].Set(wxACCEL_CTRL, 'V', IDM_PASTEGENERAL); + #if defined _MSC_VER + _CrtCheckMemory(); + #endif + + SetIcon(wxIcon(logo32_xpm)); + + /* I prefer the flat look, but that does not look right on GTK; so it is + set only on Windows */ + #if defined _WIN32 + m_btnMove->SetWindowStyle(m_btnMove->GetWindowStyle() | wxBORDER_NONE); + m_btnCopy->SetWindowStyle(m_btnCopy->GetWindowStyle() | wxBORDER_NONE); + m_btnDelete->SetWindowStyle(m_btnDelete->GetWindowStyle() | wxBORDER_NONE); + m_btnRename->SetWindowStyle(m_btnRename->GetWindowStyle() | wxBORDER_NONE); + m_btnDuplicate->SetWindowStyle(m_btnDuplicate->GetWindowStyle() | wxBORDER_NONE); + m_btnSavePart->SetWindowStyle(m_btnSavePart->GetWindowStyle() | wxBORDER_NONE); + m_btnRevertPart->SetWindowStyle(m_btnRevertPart->GetWindowStyle() | wxBORDER_NONE); + #endif + + wxAcceleratorEntry entries[9]; + entries[0].Set(wxACCEL_CTRL, '+', IDT_ZOOMIN); // Ctrl-+ + entries[1].Set(wxACCEL_CTRL, '=', IDT_ZOOMIN); // On US keyboards, Ctrl-= is needed instead of Ctrl-+ + entries[2].Set(wxACCEL_CTRL, WXK_NUMPAD_ADD, IDT_ZOOMIN); + entries[3].Set(wxACCEL_CTRL, '-', IDT_ZOOMOUT); + entries[4].Set(wxACCEL_CTRL, WXK_NUMPAD_SUBTRACT, IDT_ZOOMOUT); + entries[5].Set(wxACCEL_CTRL, 'S', IDT_SAVE); + entries[6].Set(wxACCEL_CTRL, 'Z', IDT_REVERT); + entries[7].Set(wxACCEL_CTRL, 'V', IDM_PASTEGENERAL); entries[8].Set(wxACCEL_ALT, 'X', IDC_EXPORT); - wxAcceleratorTable accel(sizearray(entries), entries); - SetAcceleratorTable(accel); - - /* add bindings for commands that are not attached to a menu item or button */ - Connect(IDM_PASTEGENERAL, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(libmngrFrame::OnPasteGeneral)); - Connect(IDC_EXPORT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(libmngrFrame::OnExportGeneral)); - - /* restore application size */ - wxFileConfig *config = new wxFileConfig(APP_NAME, VENDOR_NAME, theApp->GetINIPath()); - long w = 0, h = 0; - if (config->Read(wxT("settings/framewidth"), &w) && config->Read(wxT("settings/frameheight"), &h)) - SetSize(w, h); - if (!config->Read(wxT("settings/scale"), &Scale) || Scale < SCALE_MIN || Scale > SCALE_MAX) - Scale = SCALE_DEFAULT; - - config->Read(wxT("settings/symbolmode"), &SymbolMode, false); - m_menubar->Check(IDM_SCHEMATICMODE, SymbolMode); - config->Read(wxT("settings/comparemode"), &CompareMode, false); - m_menubar->Check(IDM_COMPAREMODE, CompareMode); - m_toolBar->EnableTool(IDT_LEFTFOOTPRINT, CompareMode); - m_toolBar->EnableTool(IDT_RIGHTFOOTPRINT, CompareMode); - if (CompareMode) { - m_toolBar->ToggleTool(IDT_LEFTFOOTPRINT, true); - m_toolBar->ToggleTool(IDT_RIGHTFOOTPRINT, true); - } - m_radioViewLeft->Enable(CompareMode); - m_radioViewRight->Enable(CompareMode); - m_radioViewLeft->SetValue(true); - config->Read(wxT("settings/syncmode"), &SyncMode, false); - m_menubar->Check(IDM_SYNCMODE, SyncMode); - - config->Read(wxT("display/footprintbkgnd"), &clrFootprintMode, wxColour(0, 0, 0)); - config->Read(wxT("display/schematicbkgnd"), &clrSchematicMode, wxColour(255, 255, 255)); - config->Read(wxT("display/3dmodelbkgnd"), &clr3DModelMode, wxColour(0, 64, 0)); - config->Read(wxT("display/showlabels"), &ShowLabels, true); - config->Read(wxT("display/centrecross"), &DrawCentreCross, true); - config->Read(wxT("display/fullpath"), &ShowFullPaths, false); - config->Read(wxT("settings/copyvrml"), &CopyVRML, true); - config->Read(wxT("settings/disabletemplate"), &DontRebuildTemplate, false); - config->Read(wxT("settings/confirmoverwrite"), &ConfirmOverwrite, true); - config->Read(wxT("settings/confirmdelete"), &ConfirmDelete, true); - config->Read(wxT("settings/reloadsession"), &ReloadSession, true); - ShowPinNumbers = true; - ShowMeasurements = true; - - #if defined NO_3DMODEL - m_toolBar->DeleteTool(IDT_3DVIEW); - #else - glCanvas = NULL; - glContext = NULL; - #endif - ModelMode = false; - - bool measurements = true; - config->Read(wxT("display/measurements"), &measurements, true); - m_toolBar->ToggleTool(IDT_MEASUREMENTS, measurements); - - long pos; - if (!config->Read(wxT("settings/splitterpanel"), &pos)) - pos = -1; - if (pos <= 0) - m_splitterViewPanel->Unsplit(); - m_menubar->Check(IDM_DETAILSPANEL, pos > 0); - m_toolBar->ToggleTool(IDT_DETAILSPANEL, pos > 0); - - FontSizeLegend = config->Read(wxT("display/fontsize"), 8L); - DimensionOffset = config->Read(wxT("display/dimoffset"), 50L); - - delete config; - - /* configure the status bar */ - int widths[] = { -1, EDITF_WIDTH }; - m_statusBar->SetFieldsCount(2, widths); - m_statusBar->SetStatusText(wxT("(no filter)"), 1); - m_editFilter = new wxSearchCtrl(m_statusBar, IDC_FILTER, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); + wxAcceleratorTable accel(sizearray(entries), entries); + SetAcceleratorTable(accel); + + /* add bindings for commands that are not attached to a menu item or button */ + Connect(IDM_PASTEGENERAL, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(libmngrFrame::OnPasteGeneral)); + Connect(IDC_EXPORT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(libmngrFrame::OnExportGeneral)); + + /* restore application size */ + wxFileConfig *config = new wxFileConfig(APP_NAME, VENDOR_NAME, theApp->GetINIPath()); + long w = 0, h = 0; + if (config->Read(wxT("settings/framewidth"), &w) && config->Read(wxT("settings/frameheight"), &h)) + SetSize(w, h); + if (!config->Read(wxT("settings/scale"), &Scale) || Scale < SCALE_MIN || Scale > SCALE_MAX) + Scale = SCALE_DEFAULT; + + config->Read(wxT("settings/symbolmode"), &SymbolMode, false); + m_menubar->Check(IDM_SCHEMATICMODE, SymbolMode); + config->Read(wxT("settings/comparemode"), &CompareMode, false); + m_menubar->Check(IDM_COMPAREMODE, CompareMode); + m_toolBar->EnableTool(IDT_LEFTFOOTPRINT, CompareMode); + m_toolBar->EnableTool(IDT_RIGHTFOOTPRINT, CompareMode); + if (CompareMode) { + m_toolBar->ToggleTool(IDT_LEFTFOOTPRINT, true); + m_toolBar->ToggleTool(IDT_RIGHTFOOTPRINT, true); + } + m_radioViewLeft->Enable(CompareMode); + m_radioViewRight->Enable(CompareMode); + m_radioViewLeft->SetValue(true); + config->Read(wxT("settings/syncmode"), &SyncMode, false); + m_menubar->Check(IDM_SYNCMODE, SyncMode); + + config->Read(wxT("display/footprintbkgnd"), &clrFootprintMode, wxColour(0, 0, 0)); + config->Read(wxT("display/schematicbkgnd"), &clrSchematicMode, wxColour(255, 255, 255)); + config->Read(wxT("display/3dmodelbkgnd"), &clr3DModelMode, wxColour(0, 64, 0)); + config->Read(wxT("display/showlabels"), &ShowLabels, true); + config->Read(wxT("display/centrecross"), &DrawCentreCross, true); + config->Read(wxT("display/fullpath"), &ShowFullPaths, false); + config->Read(wxT("settings/copyvrml"), &CopyVRML, true); + config->Read(wxT("settings/disabletemplate"), &DontRebuildTemplate, false); + config->Read(wxT("settings/confirmoverwrite"), &ConfirmOverwrite, true); + config->Read(wxT("settings/confirmdelete"), &ConfirmDelete, true); + config->Read(wxT("settings/reloadsession"), &ReloadSession, true); + ShowPinNumbers = true; + ShowMeasurements = true; + + #if defined NO_3DMODEL + m_toolBar->DeleteTool(IDT_3DVIEW); + #else + glCanvas = NULL; + glContext = NULL; + #endif + ModelMode = false; + + bool measurements = true; + config->Read(wxT("display/measurements"), &measurements, true); + m_toolBar->ToggleTool(IDT_MEASUREMENTS, measurements); + + long pos; + if (!config->Read(wxT("settings/splitterpanel"), &pos)) + pos = -1; + if (pos <= 0) + m_splitterViewPanel->Unsplit(); + m_menubar->Check(IDM_DETAILSPANEL, pos > 0); + m_toolBar->ToggleTool(IDT_DETAILSPANEL, pos > 0); + + FontSizeLegend = config->Read(wxT("display/fontsize"), 8L); + DimensionOffset = config->Read(wxT("display/dimoffset"), 50L); + + delete config; + + /* configure the status bar */ + int widths[] = { -1, EDITF_WIDTH }; + m_statusBar->SetFieldsCount(2, widths); + m_statusBar->SetStatusText(wxT("(no filter)"), 1); + m_editFilter = new wxSearchCtrl(m_statusBar, IDC_FILTER, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); m_editFilter->SetDescriptiveText(wxT("keywords")); - m_editFilter->SetToolTip(wxT("Enter one or more keywords to filter the footprints/symbols on")); + m_editFilter->SetToolTip(wxT("Enter one or more keywords to filter the footprints/symbols on")); m_editFilter->ShowCancelButton(true); - wxRect rect; - m_statusBar->GetFieldRect(1, rect); - m_editFilter->SetSize(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight(), 0); - m_editFilter->Hide(); - m_editFilter->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(libmngrFrame::OnFilterChange), NULL, this); - m_editFilter->Connect(wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler(libmngrFrame::OnFilterEnter), NULL, this); - m_editFilter->Connect(wxEVT_SEARCHCTRL_SEARCH_BTN, wxCommandEventHandler(libmngrFrame::OnFilterEnter), NULL, this); - m_editFilter->Connect(wxEVT_SEARCHCTRL_CANCEL_BTN, wxCommandEventHandler(libmngrFrame::OnFilterCancel), NULL, this); - - /* configure the list controls (columns) */ - m_listModulesLeft->InsertColumn(0, wxT("Part"), wxLIST_FORMAT_LEFT); - m_listModulesLeft->InsertColumn(1, wxT("Library"), wxLIST_FORMAT_LEFT); - m_listModulesLeft->InsertColumn(2, wxT("Path"), wxLIST_FORMAT_LEFT); - m_listModulesRight->InsertColumn(0, wxT("Part"), wxLIST_FORMAT_LEFT); - m_listModulesRight->InsertColumn(1, wxT("Library"), wxLIST_FORMAT_LEFT); - m_listModulesRight->InsertColumn(2, wxT("Path"), wxLIST_FORMAT_LEFT); - - PinData[0] = PinData[1] = NULL; - PinDataCount[0] = PinDataCount[1] = 0; - SelectedPartLeft = SelectedPartRight = -1; - PartEdited = FieldEdited = false; - - /* set starting state and labels for the buttons (no footprint/symbol selected yet) */ - ToggleMode(SymbolMode); - - #if defined NO_CURL - /* disable the repository functions in the menu */ - m_menubar->Enable(IDM_DLGREMOTE, false); - #endif - - /* set a single-shot timer to set the initial splitter positions (this action - must be delayed, because of the internals of wxWidgets) */ - m_Timer = new wxTimer(this, IDM_TIMER); - Connect(IDM_TIMER, wxEVT_TIMER, wxTimerEventHandler(libmngrFrame::OnTimer)); - m_Timer->Start(500); - - wxString path = theApp->GetFontFile(); - VFont.Read(path.mb_str(wxConvFile)); + wxRect rect; + m_statusBar->GetFieldRect(1, rect); + m_editFilter->SetSize(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight(), 0); + m_editFilter->Hide(); + m_editFilter->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(libmngrFrame::OnFilterChange), NULL, this); + m_editFilter->Connect(wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler(libmngrFrame::OnFilterEnter), NULL, this); + m_editFilter->Connect(wxEVT_SEARCHCTRL_SEARCH_BTN, wxCommandEventHandler(libmngrFrame::OnFilterEnter), NULL, this); + m_editFilter->Connect(wxEVT_SEARCHCTRL_CANCEL_BTN, wxCommandEventHandler(libmngrFrame::OnFilterCancel), NULL, this); + + /* configure the list controls (columns) */ + m_listModulesLeft->InsertColumn(0, wxT("Part"), wxLIST_FORMAT_LEFT); + m_listModulesLeft->InsertColumn(1, wxT("Library"), wxLIST_FORMAT_LEFT); + m_listModulesLeft->InsertColumn(2, wxT("Path"), wxLIST_FORMAT_LEFT); + m_listModulesRight->InsertColumn(0, wxT("Part"), wxLIST_FORMAT_LEFT); + m_listModulesRight->InsertColumn(1, wxT("Library"), wxLIST_FORMAT_LEFT); + m_listModulesRight->InsertColumn(2, wxT("Path"), wxLIST_FORMAT_LEFT); + + PinData[0] = PinData[1] = NULL; + PinDataCount[0] = PinDataCount[1] = 0; + SelectedPartLeft = SelectedPartRight = -1; + PartEdited = FieldEdited = false; + + /* set starting state and labels for the buttons (no footprint/symbol selected yet) */ + ToggleMode(SymbolMode); + + #if defined NO_CURL + /* disable the repository functions in the menu */ + m_menubar->Enable(IDM_DLGREMOTE, false); + #endif + + /* set a single-shot timer to set the initial splitter positions (this action + must be delayed, because of the internals of wxWidgets) */ + m_Timer = new wxTimer(this, IDM_TIMER); + Connect(IDM_TIMER, wxEVT_TIMER, wxTimerEventHandler(libmngrFrame::OnTimer)); + m_Timer->Start(500); + + wxString path = theApp->GetFontFile(); + VFont.Read(path.mb_str(wxConvFile)); } void libmngrFrame::OnTimer(wxTimerEvent& /*event*/) { - wxFileConfig *config = new wxFileConfig(APP_NAME, VENDOR_NAME, theApp->GetINIPath()); + wxFileConfig *config = new wxFileConfig(APP_NAME, VENDOR_NAME, theApp->GetINIPath()); int ok_count = 0; - long pos; - if (config->Read(wxT("settings/splitter"), &pos)) { + long pos; + if (config->Read(wxT("settings/splitter"), &pos)) { if (pos == m_splitter->GetSashPosition()) ok_count++; else - m_splitter->SetSashPosition(pos); + m_splitter->SetSashPosition(pos); } - if (config->Read(wxT("settings/splitterpanel"), &pos)) { + if (config->Read(wxT("settings/splitterpanel"), &pos)) { wxSize size = m_splitterViewPanel->GetSize(); if (pos <= 0 || pos == size.GetWidth() - m_splitterViewPanel->GetSashPosition()) ok_count++; else - m_splitterViewPanel->SetSashPosition(-pos); + m_splitterViewPanel->SetSashPosition(-pos); } - delete config; + delete config; static int idle_count = 0; if (ok_count == 2) { @@ -277,23 +277,23 @@ void libmngrFrame::OnTimer(wxTimerEvent& /*event*/) if (++idle_count >= 4) /* position has stayed good for 2 seconds */ m_Timer->Stop(); } else { - /* force a resize, to lay out the subfields */ - wxSize sz = GetSize(); - SetSize(sz.GetWidth() + 1, sz.GetHeight()); - SetSize(sz.GetWidth(), sz.GetHeight()); + /* force a resize, to lay out the subfields */ + wxSize sz = GetSize(); + SetSize(sz.GetWidth() + 1, sz.GetHeight()); + SetSize(sz.GetWidth(), sz.GetHeight()); idle_count = 0; } } void libmngrFrame::OnCloseApp(wxCloseEvent& event) { - CheckSavePart(); - for (int fp = 0; fp < 2; fp++) - PartData[fp].Clear(); + CheckSavePart(); + for (int fp = 0; fp < 2; fp++) + PartData[fp].Clear(); - #if !defined NO_CURL - curlCleanup(true); - #endif + #if !defined NO_CURL + curlCleanup(true); + #endif #if !defined NO_3DMODEL if (ModelMode) @@ -301,1768 +301,1768 @@ void libmngrFrame::OnCloseApp(wxCloseEvent& event) sceneGraph.clear(); #endif - wxFileConfig *config = new wxFileConfig(APP_NAME, VENDOR_NAME, theApp->GetINIPath()); + wxFileConfig *config = new wxFileConfig(APP_NAME, VENDOR_NAME, theApp->GetINIPath()); /* save the currently selected libraries and footprints/symbols */ - int idx = m_choiceModuleLeft->GetCurrentSelection(); - if (idx >= 0 && idx < (int)m_choiceModuleLeft->GetCount()) { - wxString name = m_choiceModuleLeft->GetString(idx); - if (name.length() > 0 && name[0] == wxT('(')) - name = wxEmptyString; + int idx = m_choiceModuleLeft->GetCurrentSelection(); + if (idx >= 0 && idx < (int)m_choiceModuleLeft->GetCount()) { + wxString name = m_choiceModuleLeft->GetString(idx); + if (name.length() > 0 && name[0] == wxT('(')) + name = wxEmptyString; config->Write(wxT("session/lib1"), name); - } - idx = m_choiceModuleRight->GetCurrentSelection(); - if (idx >= 0 && idx < (int)m_choiceModuleRight->GetCount()) { - wxString name = m_choiceModuleRight->GetString(idx); - if (name.length() > 0 && name[0] == wxT('(')) - name = wxEmptyString; + } + idx = m_choiceModuleRight->GetCurrentSelection(); + if (idx >= 0 && idx < (int)m_choiceModuleRight->GetCount()) { + wxString name = m_choiceModuleRight->GetString(idx); + if (name.length() > 0 && name[0] == wxT('(')) + name = wxEmptyString; config->Write(wxT("session/lib2"), name); - } + } /* save window size and settings */ - wxSize size = GetSize(); - config->Write(wxT("settings/framewidth"), size.GetWidth()); - config->Write(wxT("settings/frameheight"), size.GetHeight()); - - config->Write(wxT("settings/scale"), Scale); - config->Write(wxT("settings/symbolmode"), SymbolMode); - config->Write(wxT("settings/comparemode"), CompareMode); - config->Write(wxT("settings/syncmode"), SyncMode); - - config->Write(wxT("settings/splitter"), m_splitter->GetSashPosition()); - if (m_splitterViewPanel->IsSplit() && m_toolBar->GetToolToggled(IDT_DETAILSPANEL)) { - size = m_splitterViewPanel->GetSize(); - int pos = size.GetWidth() - m_splitterViewPanel->GetSashPosition(); - config->Write(wxT("settings/splitterpanel"), pos); - } else { - config->Write(wxT("settings/splitterpanel"), -1); - } + wxSize size = GetSize(); + config->Write(wxT("settings/framewidth"), size.GetWidth()); + config->Write(wxT("settings/frameheight"), size.GetHeight()); + + config->Write(wxT("settings/scale"), Scale); + config->Write(wxT("settings/symbolmode"), SymbolMode); + config->Write(wxT("settings/comparemode"), CompareMode); + config->Write(wxT("settings/syncmode"), SyncMode); + + config->Write(wxT("settings/splitter"), m_splitter->GetSashPosition()); + if (m_splitterViewPanel->IsSplit() && m_toolBar->GetToolToggled(IDT_DETAILSPANEL)) { + size = m_splitterViewPanel->GetSize(); + int pos = size.GetWidth() - m_splitterViewPanel->GetSashPosition(); + config->Write(wxT("settings/splitterpanel"), pos); + } else { + config->Write(wxT("settings/splitterpanel"), -1); + } - config->Write(wxT("display/measurements"), m_toolBar->GetToolToggled(IDT_MEASUREMENTS)); + config->Write(wxT("display/measurements"), m_toolBar->GetToolToggled(IDT_MEASUREMENTS)); - delete config; - event.Skip(); + delete config; + event.Skip(); } void libmngrFrame::OnNewLibrary(wxCommandEvent& /*event*/) { - wxString filter; - if (SymbolMode) - filter = wxT("Symbol libraries (*.lib)|*.lib"); - else - filter = wxT("Legacy (*.mod)|*.mod|Legacy (mm) (*.mod)|*.mod|s-expression|*.pretty"); - wxFileDialog* dlg = new wxFileDialog(this, wxT("New library..."), - wxEmptyString, wxEmptyString, - filter, wxFD_SAVE); - if (!SymbolMode) - dlg->SetFilterIndex(1); /* by default, create libraries in legacy version 2 format */ - if (dlg->ShowModal() != wxID_OK) - return; - /* set default extension */ - wxFileName fname(dlg->GetPath()); - if (fname.GetExt().length() == 0) { - if (SymbolMode) - fname.SetExt(wxT("lib")); - else if (dlg->GetFilterIndex() <= 1) - fname.SetExt(wxT("mod")); - else - fname.SetExt(wxT("pretty")); - } - - if (dlg->GetFilterIndex() <= 1) { - wxTextFile file; - if (!file.Create(fname.GetFullPath())) { - if (!file.Open(fname.GetFullPath())) { - wxMessageBox(wxT("Failed to create library ") + fname.GetFullPath()); - return; - } - } - file.Clear(); - if (SymbolMode) { - file.AddLine(wxT("EESchema-LIBRARY Version 2.3 Date: ") + wxNow()); - file.AddLine(wxT("#encoding utf-8")); - file.AddLine(wxT("#")); - file.AddLine(wxT("#End Library")); - } else { - file.AddLine(wxT("PCBNEW-LibModule-V1 ") + wxNow()); - file.AddLine(wxT("# encoding utf-8")); - if (dlg->GetFilterIndex() == 1) - file.AddLine(wxT("Units mm")); - file.AddLine(wxT("$INDEX")); - file.AddLine(wxT("$EndINDEX")); - file.AddLine(wxT("$EndLIBRARY")); - } - file.Write(); - file.Close(); - } else { - wxASSERT(!SymbolMode); - if (!wxMkdir(fname.GetFullPath())) { - wxMessageBox(wxT("Failed to create library ") + fname.GetFullPath()); - return; - } - } - - /* get current selections in the left and right combo-boxes */ - wxString leftlib; - int idx = m_choiceModuleLeft->GetCurrentSelection(); - if (idx < 0 || idx >= (int)m_choiceModuleLeft->GetCount()) - leftlib = LIB_NONE; /* assume "none" is selected when there is no selection */ - else - leftlib = m_choiceModuleLeft->GetString(idx); - wxASSERT(leftlib.length() > 0); - wxString rightlib; - idx = m_choiceModuleRight->GetCurrentSelection(); - if (idx < 0 || idx >= (int)m_choiceModuleRight->GetCount()) - rightlib = LIB_NONE; /* assume "none" is selected when there is no selection */ - else - rightlib = m_choiceModuleRight->GetString(idx); - wxASSERT(rightlib.length() > 0); - - /* refresh comboboxes */ - CollectAllLibraries(false); - EnableButtons(0); - - /* first try to restore the previous selections */ - idx = m_choiceModuleLeft->FindString(leftlib); - if (idx >= 0) - m_choiceModuleLeft->SetSelection(idx); - idx = m_choiceModuleRight->FindString(rightlib); - if (idx >= 0) - m_choiceModuleRight->SetSelection(idx); - - /* check whether to auto-select the new library - * if one of the comboboxes is set to "(None)", open it there - * if one of the comboboxes is set to "(All)" or "(Repository)", open it in the other - */ - int refresh = 0; - /* first try left box */ - if (leftlib.CmpNoCase(LIB_NONE) == 0) { - idx = m_choiceModuleLeft->FindString(fname.GetFullPath()); - if (idx >= 0) { - m_choiceModuleLeft->SetSelection(idx); - refresh = LEFTPANEL; - } - } - /* then try the right box */ - if (refresh == 0) { - if (rightlib.CmpNoCase(LIB_NONE) == 0) { - idx = m_choiceModuleRight->FindString(fname.GetFullPath()); - if (idx >= 0) { - m_choiceModuleRight->SetSelection(idx); - refresh = RIGHTPANEL; - } - } - } - /* neither has "(None)" selected, see if either has "(All)" or "(Repository)" - selected, left box first */ - if (refresh == 0) { - if (leftlib.CmpNoCase(LIB_ALL) == 0 || leftlib.CmpNoCase(LIB_REPOS) == 0) { - idx = m_choiceModuleRight->FindString(fname.GetFullPath()); - if (idx >= 0) { - m_choiceModuleRight->SetSelection(idx); - refresh = RIGHTPANEL; - } - } - } - if (refresh == 0) { - if (rightlib.CmpNoCase(LIB_ALL) == 0 || rightlib.CmpNoCase(LIB_REPOS) == 0) { - idx = m_choiceModuleLeft->FindString(fname.GetFullPath()); - if (idx >= 0) { - m_choiceModuleLeft->SetSelection(idx); - refresh = LEFTPANEL; - } - } - } - if (refresh == 0) { - /* both sides have a library selected, then just vacate the right box */ - idx = m_choiceModuleRight->FindString(fname.GetFullPath()); - if (idx >= 0) { - m_choiceModuleRight->SetSelection(idx); - refresh = RIGHTPANEL; - } - } - if (refresh == LEFTPANEL) - HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, LEFTPANEL); - else if (refresh == RIGHTPANEL) - HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, RIGHTPANEL); - SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); - m_panelView->Refresh(); + wxString filter; + if (SymbolMode) + filter = wxT("Symbol libraries (*.lib)|*.lib"); + else + filter = wxT("Legacy (*.mod)|*.mod|Legacy (mm) (*.mod)|*.mod|s-expression|*.pretty"); + wxFileDialog* dlg = new wxFileDialog(this, wxT("New library..."), + wxEmptyString, wxEmptyString, + filter, wxFD_SAVE); + if (!SymbolMode) + dlg->SetFilterIndex(1); /* by default, create libraries in legacy version 2 format */ + if (dlg->ShowModal() != wxID_OK) + return; + /* set default extension */ + wxFileName fname(dlg->GetPath()); + if (fname.GetExt().length() == 0) { + if (SymbolMode) + fname.SetExt(wxT("lib")); + else if (dlg->GetFilterIndex() <= 1) + fname.SetExt(wxT("mod")); + else + fname.SetExt(wxT("pretty")); + } + + if (dlg->GetFilterIndex() <= 1) { + wxTextFile file; + if (!file.Create(fname.GetFullPath())) { + if (!file.Open(fname.GetFullPath())) { + wxMessageBox(wxT("Failed to create library ") + fname.GetFullPath()); + return; + } + } + file.Clear(); + if (SymbolMode) { + file.AddLine(wxT("EESchema-LIBRARY Version 2.3 Date: ") + wxNow()); + file.AddLine(wxT("#encoding utf-8")); + file.AddLine(wxT("#")); + file.AddLine(wxT("#End Library")); + } else { + file.AddLine(wxT("PCBNEW-LibModule-V1 ") + wxNow()); + file.AddLine(wxT("# encoding utf-8")); + if (dlg->GetFilterIndex() == 1) + file.AddLine(wxT("Units mm")); + file.AddLine(wxT("$INDEX")); + file.AddLine(wxT("$EndINDEX")); + file.AddLine(wxT("$EndLIBRARY")); + } + file.Write(); + file.Close(); + } else { + wxASSERT(!SymbolMode); + if (!wxMkdir(fname.GetFullPath())) { + wxMessageBox(wxT("Failed to create library ") + fname.GetFullPath()); + return; + } + } + + /* get current selections in the left and right combo-boxes */ + wxString leftlib; + int idx = m_choiceModuleLeft->GetCurrentSelection(); + if (idx < 0 || idx >= (int)m_choiceModuleLeft->GetCount()) + leftlib = LIB_NONE; /* assume "none" is selected when there is no selection */ + else + leftlib = m_choiceModuleLeft->GetString(idx); + wxASSERT(leftlib.length() > 0); + wxString rightlib; + idx = m_choiceModuleRight->GetCurrentSelection(); + if (idx < 0 || idx >= (int)m_choiceModuleRight->GetCount()) + rightlib = LIB_NONE; /* assume "none" is selected when there is no selection */ + else + rightlib = m_choiceModuleRight->GetString(idx); + wxASSERT(rightlib.length() > 0); + + /* refresh comboboxes */ + CollectAllLibraries(false); + EnableButtons(0); + + /* first try to restore the previous selections */ + idx = m_choiceModuleLeft->FindString(leftlib); + if (idx >= 0) + m_choiceModuleLeft->SetSelection(idx); + idx = m_choiceModuleRight->FindString(rightlib); + if (idx >= 0) + m_choiceModuleRight->SetSelection(idx); + + /* check whether to auto-select the new library + * if one of the comboboxes is set to "(None)", open it there + * if one of the comboboxes is set to "(All)" or "(Repository)", open it in the other + */ + int refresh = 0; + /* first try left box */ + if (leftlib.CmpNoCase(LIB_NONE) == 0) { + idx = m_choiceModuleLeft->FindString(fname.GetFullPath()); + if (idx >= 0) { + m_choiceModuleLeft->SetSelection(idx); + refresh = LEFTPANEL; + } + } + /* then try the right box */ + if (refresh == 0) { + if (rightlib.CmpNoCase(LIB_NONE) == 0) { + idx = m_choiceModuleRight->FindString(fname.GetFullPath()); + if (idx >= 0) { + m_choiceModuleRight->SetSelection(idx); + refresh = RIGHTPANEL; + } + } + } + /* neither has "(None)" selected, see if either has "(All)" or "(Repository)" + selected, left box first */ + if (refresh == 0) { + if (leftlib.CmpNoCase(LIB_ALL) == 0 || leftlib.CmpNoCase(LIB_REPOS) == 0) { + idx = m_choiceModuleRight->FindString(fname.GetFullPath()); + if (idx >= 0) { + m_choiceModuleRight->SetSelection(idx); + refresh = RIGHTPANEL; + } + } + } + if (refresh == 0) { + if (rightlib.CmpNoCase(LIB_ALL) == 0 || rightlib.CmpNoCase(LIB_REPOS) == 0) { + idx = m_choiceModuleLeft->FindString(fname.GetFullPath()); + if (idx >= 0) { + m_choiceModuleLeft->SetSelection(idx); + refresh = LEFTPANEL; + } + } + } + if (refresh == 0) { + /* both sides have a library selected, then just vacate the right box */ + idx = m_choiceModuleRight->FindString(fname.GetFullPath()); + if (idx >= 0) { + m_choiceModuleRight->SetSelection(idx); + refresh = RIGHTPANEL; + } + } + if (refresh == LEFTPANEL) + HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, LEFTPANEL); + else if (refresh == RIGHTPANEL) + HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, RIGHTPANEL); + SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); + m_panelView->Refresh(); } bool libmngrFrame::GetSelectedLibrary(wxString* library, int *side) { - /* first check which library to add the footprint/symbol to (or which to rename) */ - wxString leftname, rightname; - int idx = m_choiceModuleLeft->GetCurrentSelection(); - if (idx >= 0 && idx < (int)m_choiceModuleLeft->GetCount()) { - leftname = m_choiceModuleLeft->GetString(idx); - if (leftname.length() > 0 && leftname[0] == wxT('(')) - leftname = wxEmptyString; - } - idx = m_choiceModuleRight->GetCurrentSelection(); - if (idx >= 0 && idx < (int)m_choiceModuleRight->GetCount()) { - rightname = m_choiceModuleRight->GetString(idx); - if (rightname.length() > 0 && rightname[0] == wxT('(')) - rightname = wxEmptyString; - } - wxString filename; - if (leftname.length() > 0 && rightname.length() > 0 && leftname.CmpNoCase(rightname) != 0) { - wxArrayString choices; - choices.Add(leftname); - choices.Add(rightname); - wxSingleChoiceDialog dlg(this, wxT("Select library"), wxT("Library"), choices); - if (dlg.ShowModal() != wxID_OK) - return false; - filename = dlg.GetStringSelection(); - } else if (leftname.length() > 0) { - filename = leftname; - } else if (rightname.length() > 0) { - filename = rightname; - } else { - wxASSERT(leftname.length() == 0 && rightname.length() == 0); - wxMessageBox(wxT("No local library is selected.")); - return false; - } - - wxASSERT(side != NULL); - *side = 0; - if (filename.Cmp(leftname) == 0) - *side -= 1; - if (filename.Cmp(rightname) == 0) - *side += 1; - /* if at the end of this procedure, side == 0, it is equal to both left and right */ - - wxASSERT(library != NULL); - *library = filename; - return true; + /* first check which library to add the footprint/symbol to (or which to rename) */ + wxString leftname, rightname; + int idx = m_choiceModuleLeft->GetCurrentSelection(); + if (idx >= 0 && idx < (int)m_choiceModuleLeft->GetCount()) { + leftname = m_choiceModuleLeft->GetString(idx); + if (leftname.length() > 0 && leftname[0] == wxT('(')) + leftname = wxEmptyString; + } + idx = m_choiceModuleRight->GetCurrentSelection(); + if (idx >= 0 && idx < (int)m_choiceModuleRight->GetCount()) { + rightname = m_choiceModuleRight->GetString(idx); + if (rightname.length() > 0 && rightname[0] == wxT('(')) + rightname = wxEmptyString; + } + wxString filename; + if (leftname.length() > 0 && rightname.length() > 0 && leftname.CmpNoCase(rightname) != 0) { + wxArrayString choices; + choices.Add(leftname); + choices.Add(rightname); + wxSingleChoiceDialog dlg(this, wxT("Select library"), wxT("Library"), choices); + if (dlg.ShowModal() != wxID_OK) + return false; + filename = dlg.GetStringSelection(); + } else if (leftname.length() > 0) { + filename = leftname; + } else if (rightname.length() > 0) { + filename = rightname; + } else { + wxASSERT(leftname.length() == 0 && rightname.length() == 0); + wxMessageBox(wxT("No local library is selected.")); + return false; + } + + wxASSERT(side != NULL); + *side = 0; + if (filename.Cmp(leftname) == 0) + *side -= 1; + if (filename.Cmp(rightname) == 0) + *side += 1; + /* if at the end of this procedure, side == 0, it is equal to both left and right */ + + wxASSERT(library != NULL); + *library = filename; + return true; } void libmngrFrame::OnRenameLibrary(wxCommandEvent& /*event*/) { - /* first check which library to rename */ - int side; - wxString filename; - if (!GetSelectedLibrary(&filename, &side)) - return; - - /* split the path off */ - wxASSERT(filename.length() > 0); - wxFileName old_fname(filename); - - wxTextEntryDialog dlg(this, wxT("New name"), wxT("Rename ") + old_fname.GetName(), old_fname.GetName()); - if (dlg.ShowModal() == wxID_OK) { - filename = dlg.GetValue(); - wxFileName new_fname(filename); - new_fname.SetPath(old_fname.GetPath()); /* remove any path the user typed in, set the path of the old library */ - new_fname.SetExt(old_fname.GetExt()); - bool ok = wxRenameFile(old_fname.GetFullPath(), new_fname.GetFullPath(), false); - if (ok) { - /* refresh comboboxes */ - CollectAllLibraries(false); - EnableButtons(0); - /* load the renamed library */ - if (side <= 0) { - int idx = m_choiceModuleLeft->FindString(new_fname.GetFullPath()); - if (idx >= 0) - m_choiceModuleLeft->SetSelection(idx); - HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, LEFTPANEL); - } - if (side >= 0) { - int idx = m_choiceModuleRight->FindString(new_fname.GetFullPath()); - if (idx >= 0) - m_choiceModuleRight->SetSelection(idx); - HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, RIGHTPANEL); - } - SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); - m_panelView->Refresh(); - } else { - wxMessageBox(wxT("Failed to rename the library (access denied or conflicting names)")); - } - } + /* first check which library to rename */ + int side; + wxString filename; + if (!GetSelectedLibrary(&filename, &side)) + return; + + /* split the path off */ + wxASSERT(filename.length() > 0); + wxFileName old_fname(filename); + + wxTextEntryDialog dlg(this, wxT("New name"), wxT("Rename ") + old_fname.GetName(), old_fname.GetName()); + if (dlg.ShowModal() == wxID_OK) { + filename = dlg.GetValue(); + wxFileName new_fname(filename); + new_fname.SetPath(old_fname.GetPath()); /* remove any path the user typed in, set the path of the old library */ + new_fname.SetExt(old_fname.GetExt()); + bool ok = wxRenameFile(old_fname.GetFullPath(), new_fname.GetFullPath(), false); + if (ok) { + /* refresh comboboxes */ + CollectAllLibraries(false); + EnableButtons(0); + /* load the renamed library */ + if (side <= 0) { + int idx = m_choiceModuleLeft->FindString(new_fname.GetFullPath()); + if (idx >= 0) + m_choiceModuleLeft->SetSelection(idx); + HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, LEFTPANEL); + } + if (side >= 0) { + int idx = m_choiceModuleRight->FindString(new_fname.GetFullPath()); + if (idx >= 0) + m_choiceModuleRight->SetSelection(idx); + HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, RIGHTPANEL); + } + SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); + m_panelView->Refresh(); + } else { + wxMessageBox(wxT("Failed to rename the library (access denied or conflicting names)")); + } + } } void libmngrFrame::OnNewFootprint(wxCommandEvent& /*event*/) { - if (CompareMode) { - wxMessageBox(wxT("Compare mode must be switched off.")); - return; - } - if (SymbolMode) { - wxMessageBox(wxT("Footprint mode must be selected (instead of Schematic mode).")); - return; - } - CheckSavePart(); - - /* first check which library to add the footprint to */ - int side; - wxString filename; - if (!GetSelectedLibrary(&filename, &side)) - return; - m_radioViewLeft->SetValue(side <= 0); - m_radioViewRight->SetValue(side > 0); - - /* set the dialog for the template */ - libmngrDlgNewFootprint dlg(this); - dlg.SetLibraryName(filename); - if (dlg.ShowModal() == wxID_OK) { - /* load the template */ - wxArrayString templat; - LoadTemplate(dlg.GetTemplateName(), &templat, false); - /* extract the number of pins from the footprint name (this may fail - and the template may overrule it; it is just a heuristic) */ - long pins = 0; - wxString name = dlg.GetFootprintName(); - size_t len = name.Length(); - while (len > 0 && isdigit(name[len - 1])) - len--; - if (len > 0) { - name = name.Mid(len); - name.ToLong(&pins); - if (pins > 100 || !ValidPinCount(pins, dlg.GetTemplateName(), false)) /* must match the #pins line in the header */ - pins = 0; - } - /* verify that the name is valid */ - wxString newname = dlg.GetFootprintName(); - int targettype = LibraryType(filename); - if (targettype == VER_S_EXPR && !ValidateFilename(&newname)) - return; - /* run over the expressions to create the initial shape */ - RPNexpression rpn; - wxString description = GetTemplateHeaderField(dlg.GetTemplateName(), wxT("brief"), SymbolMode); - if (pins > 0) - rpn.SetVariable(RPNvariable("PT", pins)); - SetVarDefaults(&rpn, dlg.GetTemplateName(), newname, description); - SetVarsFromTemplate(&rpn, dlg.GetTemplateName(), false); - /* create a footprint from the template */ - wxArrayString module; - if (!FootprintFromTemplate(&module, templat, rpn, false)) - return; /* error message(s) already given */ - if (targettype == VER_INVALID) { - wxMessageBox(wxT("Unsupported file format for the target library.")); - return; - } if (targettype == VER_S_EXPR) { - /* translate the module to s-expression */ - wxArrayString tmpmod = module; - TranslateToSexpr(&module, tmpmod); - } - /* save the footprint with initial settings (may need to erase the footprint - first) */ - if (ExistFootprint(filename, newname)) - RemoveFootprint(filename, newname); - if (!InsertFootprint(filename, newname, module, true)) { - wxMessageBox(wxT("Operation failed.")); - return; - } - wxString vrmlpath = GetVRMLPath(filename, module); - if (vrmlpath.Length() > 0) { - wxString modelname = GetTemplateHeaderField(dlg.GetTemplateName(), wxT("model"), SymbolMode); - if (modelname.length() == 0) - modelname = dlg.GetTemplateName(); - else + if (CompareMode) { + wxMessageBox(wxT("Compare mode must be switched off.")); + return; + } + if (SymbolMode) { + wxMessageBox(wxT("Footprint mode must be selected (instead of Schematic mode).")); + return; + } + CheckSavePart(); + + /* first check which library to add the footprint to */ + int side; + wxString filename; + if (!GetSelectedLibrary(&filename, &side)) + return; + m_radioViewLeft->SetValue(side <= 0); + m_radioViewRight->SetValue(side > 0); + + /* set the dialog for the template */ + libmngrDlgNewFootprint dlg(this); + dlg.SetLibraryName(filename); + if (dlg.ShowModal() == wxID_OK) { + /* load the template */ + wxArrayString templat; + LoadTemplate(dlg.GetTemplateName(), &templat, false); + /* extract the number of pins from the footprint name (this may fail + and the template may overrule it; it is just a heuristic) */ + long pins = 0; + wxString name = dlg.GetFootprintName(); + size_t len = name.Length(); + while (len > 0 && isdigit(name[len - 1])) + len--; + if (len > 0) { + name = name.Mid(len); + name.ToLong(&pins); + if (pins > 100 || !ValidPinCount(pins, dlg.GetTemplateName(), false)) /* must match the #pins line in the header */ + pins = 0; + } + /* verify that the name is valid */ + wxString newname = dlg.GetFootprintName(); + int targettype = LibraryType(filename); + if (targettype == VER_S_EXPR && !ValidateFilename(&newname)) + return; + /* run over the expressions to create the initial shape */ + RPNexpression rpn; + wxString description = GetTemplateHeaderField(dlg.GetTemplateName(), wxT("brief"), SymbolMode); + if (pins > 0) + rpn.SetVariable(RPNvariable("PT", pins)); + SetVarDefaults(&rpn, dlg.GetTemplateName(), newname, description); + SetVarsFromTemplate(&rpn, dlg.GetTemplateName(), false); + /* create a footprint from the template */ + wxArrayString module; + if (!FootprintFromTemplate(&module, templat, rpn, false)) + return; /* error message(s) already given */ + if (targettype == VER_INVALID) { + wxMessageBox(wxT("Unsupported file format for the target library.")); + return; + } if (targettype == VER_S_EXPR) { + /* translate the module to s-expression */ + wxArrayString tmpmod = module; + TranslateToSexpr(&module, tmpmod); + } + /* save the footprint with initial settings (may need to erase the footprint + first) */ + if (ExistFootprint(filename, newname)) + RemoveFootprint(filename, newname); + if (!InsertFootprint(filename, newname, module, true)) { + wxMessageBox(wxT("Operation failed.")); + return; + } + wxString vrmlpath = GetVRMLPath(filename, module); + if (vrmlpath.Length() > 0) { + wxString modelname = GetTemplateHeaderField(dlg.GetTemplateName(), wxT("model"), SymbolMode); + if (modelname.length() == 0) + modelname = dlg.GetTemplateName(); + else modelname = modelname.BeforeFirst(wxT(' ')); /* use first model (there may be more) */ - VRMLFromTemplate(vrmlpath, modelname, rpn); - } - /* refresh the library (or possibly both, if both lists contain the same library) */ - if (side <= 0) - HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, LEFTPANEL); - if (side >= 0) - HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, RIGHTPANEL); - SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); - /* load the newly created part */ - RemoveSelection(m_listModulesLeft, &SelectedPartLeft); - RemoveSelection(m_listModulesRight, &SelectedPartRight); - OffsetX = OffsetY = 0; - wxListCtrl* list = (side <= 0) ? m_listModulesLeft : m_listModulesRight; - wxBusyCursor cursor; - /* get the index of the new part in the footprint list */ - int idx; - for (idx = 0; idx < list->GetItemCount(); idx++) { - wxString symbol = list->GetItemText(idx); - if (symbol.Cmp(dlg.GetFootprintName()) == 0) - break; - } - wxASSERT(idx < list->GetItemCount()); /* it was just inserted, so it must be found */ - list->SetItemState(idx, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED); - list->EnsureVisible(idx); - LoadPart(idx, list, 0, 0); - UpdateDetails(0); + VRMLFromTemplate(vrmlpath, modelname, rpn); + } + /* refresh the library (or possibly both, if both lists contain the same library) */ + if (side <= 0) + HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, LEFTPANEL); + if (side >= 0) + HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, RIGHTPANEL); + SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); + /* load the newly created part */ + RemoveSelection(m_listModulesLeft, &SelectedPartLeft); + RemoveSelection(m_listModulesRight, &SelectedPartRight); + OffsetX = OffsetY = 0; + wxListCtrl* list = (side <= 0) ? m_listModulesLeft : m_listModulesRight; + wxBusyCursor cursor; + /* get the index of the new part in the footprint list */ + int idx; + for (idx = 0; idx < list->GetItemCount(); idx++) { + wxString symbol = list->GetItemText(idx); + if (symbol.Cmp(dlg.GetFootprintName()) == 0) + break; + } + wxASSERT(idx < list->GetItemCount()); /* it was just inserted, so it must be found */ + list->SetItemState(idx, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED); + list->EnsureVisible(idx); + LoadPart(idx, list, 0, 0); + UpdateDetails(0); Update3DModel(PartData[0]); - m_panelView->Refresh(); - m_statusBar->SetStatusText(wxT("New footprint")); - /* toggle the details panel on, if it was off */ - bool details = m_menubar->IsChecked(IDM_DETAILSPANEL); - if (!details) { - m_menubar->Check(IDM_DETAILSPANEL, true); - m_toolBar->ToggleTool(IDT_DETAILSPANEL, true); - ToggleDetailsPanel(true); - } - } + m_panelView->Refresh(); + m_statusBar->SetStatusText(wxT("New footprint")); + /* toggle the details panel on, if it was off */ + bool details = m_menubar->IsChecked(IDM_DETAILSPANEL); + if (!details) { + m_menubar->Check(IDM_DETAILSPANEL, true); + m_toolBar->ToggleTool(IDT_DETAILSPANEL, true); + ToggleDetailsPanel(true); + } + } } void libmngrFrame::OnNewSymbol(wxCommandEvent& /*event*/) { - if (CompareMode) { - wxMessageBox(wxT("Compare mode must be switched off.")); - return; - } - if (!SymbolMode) { - wxMessageBox(wxT("Schematic mode must be selected (instead of Footprint mode).")); - return; - } - CheckSavePart(); - - /* first check which library to add the footprint to */ - wxString filename; - int side; - if (!GetSelectedLibrary(&filename, &side)) - return; - m_radioViewLeft->SetValue(side <= 0); - m_radioViewRight->SetValue(side > 0); - - /* set the dialog for the template */ - libmngrDlgNewSymbol dlg(this); - dlg.SetLibraryName(filename); - if (dlg.ShowModal() == wxID_OK) { - /* load the template */ - wxArrayString templat; - LoadTemplate(dlg.GetTemplateName(), &templat, true); - GetTemplateSections(dlg.GetTemplateName(), CustomPinSections[0], sizearray(CustomPinSections[0])); - /* run over the expressions to create the initial shape */ - RPNexpression rpn; - wxString description = GetTemplateHeaderField(dlg.GetTemplateName(), wxT("brief"), SymbolMode); - SetVarDefaults(&rpn, dlg.GetTemplateName(), dlg.GetSymbolName(), description, dlg.GetSymbolRef()); - /* create default pin info structure from the pin count */ - int pins = 0; - rpn.Set("PT"); - if (rpn.Parse() == RPN_OK) { - RPNvalue v = rpn.Value(); - pins = (int)(v.Double() + 0.001); - } - if (pins == 0) - pins = 2; /* this is actually a template error; PT should be set */ - PinInfo* info = new PinInfo[pins]; - if (info == NULL) - return; - int totals[PinInfo::SectionCount]; - int counts[PinInfo::SectionCount]; - for (int s = 0; s < PinInfo::SectionCount; s++) { - totals[s] = 0; - counts[s] = 0; - char str[20]; - sprintf(str, "PT:%d", s); - rpn.Set(str); - if (rpn.Parse() == RPN_OK) { - RPNvalue v = rpn.Value(); - totals[s] = (int)(v.Double() + 0.001); - } - } - int cursec = PinInfo::Left; - for (int i = 0; i < pins; i++) { - while (cursec < PinInfo::SectionCount && counts[cursec] >= totals[cursec]) - cursec++; - if (cursec >= PinInfo::SectionCount) - cursec = PinInfo::Left; /* on error, map remaining pins to left side */ - counts[cursec] += 1; - info[i].seq = i; - info[i].number = wxString::Format(wxT("%d"), i + 1); - info[i].name = wxT("~"); - info[i].type = PinInfo::Passive; - info[i].shape = PinInfo::Line; - info[i].section = cursec; - info[i].part = 0; - } - /* create a footprint from the template */ - wxArrayString symbol; - bool result = SymbolFromTemplate(&symbol, templat, rpn, info, pins); - delete[] info; - if (!result) - return; /* error message(s) already given */ - /* save the symbol with initial settings (may need to erase the symbol first) */ - if (ExistSymbol(filename, dlg.GetSymbolName())) - RemoveSymbol(filename, dlg.GetSymbolName()); - if (!InsertSymbol(filename, dlg.GetSymbolName(), symbol)) { - wxMessageBox(wxT("Operation failed.")); - return; - } - /* refresh the library (or possibly both, if both lists contain the same library) */ - if (side <= 0) - HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, LEFTPANEL); - if (side >= 0) - HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, RIGHTPANEL); - SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); - /* load the newly created part */ - RemoveSelection(m_listModulesLeft, &SelectedPartLeft); - RemoveSelection(m_listModulesRight, &SelectedPartRight); - OffsetX = OffsetY = 0; - wxListCtrl* list = (side <= 0) ? m_listModulesLeft : m_listModulesRight; - wxBusyCursor cursor; - /* get the index of the new part in the footprint list */ - int idx; - for (idx = 0; idx < list->GetItemCount(); idx++) { - wxString symbol = list->GetItemText(idx); - if (symbol.Cmp(dlg.GetSymbolName()) == 0) - break; - } - wxASSERT(idx < list->GetItemCount()); /* it was just inserted, so it must be found */ - list->SetItemState(idx, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED); - list->EnsureVisible(idx); - LoadPart(idx, list, 0, 0); - UpdateDetails(0); - m_panelView->Refresh(); - m_statusBar->SetStatusText(wxT("New symbol")); - /* toggle the details panel on, if it was off */ - bool details = m_menubar->IsChecked(IDM_DETAILSPANEL); - if (!details) { - m_menubar->Check(IDM_DETAILSPANEL, true); - m_toolBar->ToggleTool(IDT_DETAILSPANEL, true); - ToggleDetailsPanel(true); - } - } + if (CompareMode) { + wxMessageBox(wxT("Compare mode must be switched off.")); + return; + } + if (!SymbolMode) { + wxMessageBox(wxT("Schematic mode must be selected (instead of Footprint mode).")); + return; + } + CheckSavePart(); + + /* first check which library to add the footprint to */ + wxString filename; + int side; + if (!GetSelectedLibrary(&filename, &side)) + return; + m_radioViewLeft->SetValue(side <= 0); + m_radioViewRight->SetValue(side > 0); + + /* set the dialog for the template */ + libmngrDlgNewSymbol dlg(this); + dlg.SetLibraryName(filename); + if (dlg.ShowModal() == wxID_OK) { + /* load the template */ + wxArrayString templat; + LoadTemplate(dlg.GetTemplateName(), &templat, true); + GetTemplateSections(dlg.GetTemplateName(), CustomPinSections[0], sizearray(CustomPinSections[0])); + /* run over the expressions to create the initial shape */ + RPNexpression rpn; + wxString description = GetTemplateHeaderField(dlg.GetTemplateName(), wxT("brief"), SymbolMode); + SetVarDefaults(&rpn, dlg.GetTemplateName(), dlg.GetSymbolName(), description, dlg.GetSymbolRef()); + /* create default pin info structure from the pin count */ + int pins = 0; + rpn.Set("PT"); + if (rpn.Parse() == RPN_OK) { + RPNvalue v = rpn.Value(); + pins = (int)(v.Double() + 0.001); + } + if (pins == 0) + pins = 2; /* this is actually a template error; PT should be set */ + PinInfo* info = new PinInfo[pins]; + if (info == NULL) + return; + int totals[PinInfo::SectionCount]; + int counts[PinInfo::SectionCount]; + for (int s = 0; s < PinInfo::SectionCount; s++) { + totals[s] = 0; + counts[s] = 0; + char str[20]; + sprintf(str, "PT:%d", s); + rpn.Set(str); + if (rpn.Parse() == RPN_OK) { + RPNvalue v = rpn.Value(); + totals[s] = (int)(v.Double() + 0.001); + } + } + int cursec = PinInfo::Left; + for (int i = 0; i < pins; i++) { + while (cursec < PinInfo::SectionCount && counts[cursec] >= totals[cursec]) + cursec++; + if (cursec >= PinInfo::SectionCount) + cursec = PinInfo::Left; /* on error, map remaining pins to left side */ + counts[cursec] += 1; + info[i].seq = i; + info[i].number = wxString::Format(wxT("%d"), i + 1); + info[i].name = wxT("~"); + info[i].type = PinInfo::Passive; + info[i].shape = PinInfo::Line; + info[i].section = cursec; + info[i].part = 0; + } + /* create a footprint from the template */ + wxArrayString symbol; + bool result = SymbolFromTemplate(&symbol, templat, rpn, info, pins); + delete[] info; + if (!result) + return; /* error message(s) already given */ + /* save the symbol with initial settings (may need to erase the symbol first) */ + if (ExistSymbol(filename, dlg.GetSymbolName())) + RemoveSymbol(filename, dlg.GetSymbolName()); + if (!InsertSymbol(filename, dlg.GetSymbolName(), symbol)) { + wxMessageBox(wxT("Operation failed.")); + return; + } + /* refresh the library (or possibly both, if both lists contain the same library) */ + if (side <= 0) + HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, LEFTPANEL); + if (side >= 0) + HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, RIGHTPANEL); + SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); + /* load the newly created part */ + RemoveSelection(m_listModulesLeft, &SelectedPartLeft); + RemoveSelection(m_listModulesRight, &SelectedPartRight); + OffsetX = OffsetY = 0; + wxListCtrl* list = (side <= 0) ? m_listModulesLeft : m_listModulesRight; + wxBusyCursor cursor; + /* get the index of the new part in the footprint list */ + int idx; + for (idx = 0; idx < list->GetItemCount(); idx++) { + wxString symbol = list->GetItemText(idx); + if (symbol.Cmp(dlg.GetSymbolName()) == 0) + break; + } + wxASSERT(idx < list->GetItemCount()); /* it was just inserted, so it must be found */ + list->SetItemState(idx, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED); + list->EnsureVisible(idx); + LoadPart(idx, list, 0, 0); + UpdateDetails(0); + m_panelView->Refresh(); + m_statusBar->SetStatusText(wxT("New symbol")); + /* toggle the details panel on, if it was off */ + bool details = m_menubar->IsChecked(IDM_DETAILSPANEL); + if (!details) { + m_menubar->Check(IDM_DETAILSPANEL, true); + m_toolBar->ToggleTool(IDT_DETAILSPANEL, true); + ToggleDetailsPanel(true); + } + } } bool libmngrFrame::GetReportNameList(wxString* reportfile, wxString* library, wxArrayString* namelist) { - /* find which library to print */ - wxString leftname, rightname; - int idx = m_choiceModuleLeft->GetCurrentSelection(); - if (idx >= 0 && idx < (int)m_choiceModuleLeft->GetCount()) { - leftname = m_choiceModuleLeft->GetString(idx); - if (leftname.length() > 0 && leftname[0] == wxT('(')) - leftname = wxEmptyString; - } - idx = m_choiceModuleRight->GetCurrentSelection(); - if (idx >= 0 && idx < (int)m_choiceModuleRight->GetCount()) { - rightname = m_choiceModuleRight->GetString(idx); - if (rightname.length() > 0 && rightname[0] == wxT('(')) - rightname = wxEmptyString; - } - wxASSERT(library != NULL); - if (leftname.length() > 0 && rightname.length() > 0) { - wxArrayString choices; - choices.Add(leftname); - choices.Add(rightname); - wxSingleChoiceDialog dlg(this, wxT("Select library"), wxT("Library"), choices); - if (dlg.ShowModal() != wxID_OK) - return false; - *library = dlg.GetStringSelection(); - } else if (leftname.length() > 0) { - *library = leftname; - } else if (rightname.length() > 0) { - *library = rightname; - } else { - wxASSERT(leftname.length() == 0 && rightname.length() == 0); - wxMessageBox(wxT("No local library is selected.")); - return false; - } - - /* get the name of the report file */ - wxFileName fname(*library); - fname.SetExt(wxT("pdf")); - wxFileDialog* dlg = new wxFileDialog(this, wxT("Choose report filename..."), - wxEmptyString, fname.GetFullPath(), - wxT("Acrobat PDF (*.pdf)|*.pdf"), - wxFD_SAVE); - if (dlg->ShowModal() != wxID_OK) - return false; - /* set default extension */ - fname.Assign(dlg->GetPath()); - if (fname.GetExt().length() == 0) - fname.SetExt(wxT("pdf")); - wxASSERT(reportfile != NULL); - *reportfile = fname.GetFullPath(); - - /* collect the list of footprint names to print */ - wxListCtrl* list; - if (library->Cmp(leftname) == 0) - list = m_listModulesLeft; - else - list = m_listModulesRight; - wxASSERT(namelist != NULL); - namelist->Clear(); - for (long idx = 0; idx < list->GetItemCount(); idx++) - namelist->Add(list->GetItemText(idx)); - - return true; + /* find which library to print */ + wxString leftname, rightname; + int idx = m_choiceModuleLeft->GetCurrentSelection(); + if (idx >= 0 && idx < (int)m_choiceModuleLeft->GetCount()) { + leftname = m_choiceModuleLeft->GetString(idx); + if (leftname.length() > 0 && leftname[0] == wxT('(')) + leftname = wxEmptyString; + } + idx = m_choiceModuleRight->GetCurrentSelection(); + if (idx >= 0 && idx < (int)m_choiceModuleRight->GetCount()) { + rightname = m_choiceModuleRight->GetString(idx); + if (rightname.length() > 0 && rightname[0] == wxT('(')) + rightname = wxEmptyString; + } + wxASSERT(library != NULL); + if (leftname.length() > 0 && rightname.length() > 0) { + wxArrayString choices; + choices.Add(leftname); + choices.Add(rightname); + wxSingleChoiceDialog dlg(this, wxT("Select library"), wxT("Library"), choices); + if (dlg.ShowModal() != wxID_OK) + return false; + *library = dlg.GetStringSelection(); + } else if (leftname.length() > 0) { + *library = leftname; + } else if (rightname.length() > 0) { + *library = rightname; + } else { + wxASSERT(leftname.length() == 0 && rightname.length() == 0); + wxMessageBox(wxT("No local library is selected.")); + return false; + } + + /* get the name of the report file */ + wxFileName fname(*library); + fname.SetExt(wxT("pdf")); + wxFileDialog* dlg = new wxFileDialog(this, wxT("Choose report filename..."), + wxEmptyString, fname.GetFullPath(), + wxT("Acrobat PDF (*.pdf)|*.pdf"), + wxFD_SAVE); + if (dlg->ShowModal() != wxID_OK) + return false; + /* set default extension */ + fname.Assign(dlg->GetPath()); + if (fname.GetExt().length() == 0) + fname.SetExt(wxT("pdf")); + wxASSERT(reportfile != NULL); + *reportfile = fname.GetFullPath(); + + /* collect the list of footprint names to print */ + wxListCtrl* list; + if (library->Cmp(leftname) == 0) + list = m_listModulesLeft; + else + list = m_listModulesRight; + wxASSERT(namelist != NULL); + namelist->Clear(); + for (long idx = 0; idx < list->GetItemCount(); idx++) + namelist->Add(list->GetItemText(idx)); + + return true; } void libmngrFrame::OnFootprintReport(wxCommandEvent& /*event*/) { - wxString reportfile; - wxString library; - wxArrayString modules; - if (!GetReportNameList(&reportfile, &library, &modules)) - return; - - /* print the library, then show the report */ - wxString format; - wxFileConfig *config = new wxFileConfig(APP_NAME, VENDOR_NAME, theApp->GetINIPath()); - format = config->Read(wxT("report/paper"), wxT("Letter")); - long landscape = config->Read(wxT("report/layout"), 0L); - long opt_labels = config->Read(wxT("report/drawlabels"), 0L); - long opt_description = config->Read(wxT("report/includedescription"), 1L); - long opt_padinfo = config->Read(wxT("report/includepadinfo"), 1L); - long fontsize = config->Read(wxT("report/fontsize"), 8L); - delete config; - PdfReport report; - report.SetPage(format, (landscape != 0)); - report.FootprintOptions(opt_description != 0, opt_padinfo != 0, opt_labels != 0); - report.SetFont(fontsize); - report.FootprintReport(this, library, modules, reportfile); - m_statusBar->SetStatusText(wxT("Finished report")); - - #if wxMAJOR_VERSION < 3 - wxTheMimeTypesManager->ReadMailcap(wxT("/etc/mailcap")); /* for wxWidgets 2.8 */ - #endif - wxFileType *FileType = wxTheMimeTypesManager->GetFileTypeFromMimeType(wxT("application/pdf")); - wxString Command = FileType->GetOpenCommand(reportfile); - /* sometimes wildcards remain in the command */ - int pos; - while ((pos = Command.Find(wxT('*'))) >= 0) - Command.Remove(pos, 1); - Command.Trim(); - /* finally, run it */ - wxExecute(Command); + wxString reportfile; + wxString library; + wxArrayString modules; + if (!GetReportNameList(&reportfile, &library, &modules)) + return; + + /* print the library, then show the report */ + wxString format; + wxFileConfig *config = new wxFileConfig(APP_NAME, VENDOR_NAME, theApp->GetINIPath()); + format = config->Read(wxT("report/paper"), wxT("Letter")); + long landscape = config->Read(wxT("report/layout"), 0L); + long opt_labels = config->Read(wxT("report/drawlabels"), 0L); + long opt_description = config->Read(wxT("report/includedescription"), 1L); + long opt_padinfo = config->Read(wxT("report/includepadinfo"), 1L); + long fontsize = config->Read(wxT("report/fontsize"), 8L); + delete config; + PdfReport report; + report.SetPage(format, (landscape != 0)); + report.FootprintOptions(opt_description != 0, opt_padinfo != 0, opt_labels != 0); + report.SetFont(fontsize); + report.FootprintReport(this, library, modules, reportfile); + m_statusBar->SetStatusText(wxT("Finished report")); + + #if wxMAJOR_VERSION < 3 + wxTheMimeTypesManager->ReadMailcap(wxT("/etc/mailcap")); /* for wxWidgets 2.8 */ + #endif + wxFileType *FileType = wxTheMimeTypesManager->GetFileTypeFromMimeType(wxT("application/pdf")); + wxString Command = FileType->GetOpenCommand(reportfile); + /* sometimes wildcards remain in the command */ + int pos; + while ((pos = Command.Find(wxT('*'))) >= 0) + Command.Remove(pos, 1); + Command.Trim(); + /* finally, run it */ + wxExecute(Command); } void libmngrFrame::OnSymbolReport(wxCommandEvent& /*event*/) { - wxString reportfile; - wxString library; - wxArrayString symbols; - if (!GetReportNameList(&reportfile, &library, &symbols)) - return; - - /* print the library, then show the report */ - wxString format; - wxFileConfig *config = new wxFileConfig(APP_NAME, VENDOR_NAME, theApp->GetINIPath()); - format = config->Read(wxT("report/paper"), wxT("Letter")); - long landscape = config->Read(wxT("report/layout"), 0L); - long fontsize = config->Read(wxT("report/fontsize"), 8L); - long opt_description = config->Read(wxT("report/includedescription"), 1L); - long opt_fplist = config->Read(wxT("report/fplist"), 1L); - delete config; - PdfReport report; - report.SetPage(format, (landscape != 0)); - report.SymbolOptions(opt_description != 0, opt_fplist != 0); - report.SetFont(fontsize); - report.SymbolReport(this, library, symbols, reportfile); - m_statusBar->SetStatusText(wxT("Finished report")); - - #if wxMAJOR_VERSION < 3 - wxTheMimeTypesManager->ReadMailcap(wxT("/etc/mailcap")); - #endif - wxFileType *FileType = wxTheMimeTypesManager->GetFileTypeFromMimeType(wxT("application/pdf")); - wxString Command = FileType->GetOpenCommand(reportfile); - /* sometimes wildcards remain in the command */ - int pos; - while ((pos = Command.Find(wxT('*'))) >= 0) - Command.Remove(pos, 1); - Command.Trim(); - /* finally, run it */ - wxExecute(Command); + wxString reportfile; + wxString library; + wxArrayString symbols; + if (!GetReportNameList(&reportfile, &library, &symbols)) + return; + + /* print the library, then show the report */ + wxString format; + wxFileConfig *config = new wxFileConfig(APP_NAME, VENDOR_NAME, theApp->GetINIPath()); + format = config->Read(wxT("report/paper"), wxT("Letter")); + long landscape = config->Read(wxT("report/layout"), 0L); + long fontsize = config->Read(wxT("report/fontsize"), 8L); + long opt_description = config->Read(wxT("report/includedescription"), 1L); + long opt_fplist = config->Read(wxT("report/fplist"), 1L); + delete config; + PdfReport report; + report.SetPage(format, (landscape != 0)); + report.SymbolOptions(opt_description != 0, opt_fplist != 0); + report.SetFont(fontsize); + report.SymbolReport(this, library, symbols, reportfile); + m_statusBar->SetStatusText(wxT("Finished report")); + + #if wxMAJOR_VERSION < 3 + wxTheMimeTypesManager->ReadMailcap(wxT("/etc/mailcap")); + #endif + wxFileType *FileType = wxTheMimeTypesManager->GetFileTypeFromMimeType(wxT("application/pdf")); + wxString Command = FileType->GetOpenCommand(reportfile); + /* sometimes wildcards remain in the command */ + int pos; + while ((pos = Command.Find(wxT('*'))) >= 0) + Command.Remove(pos, 1); + Command.Trim(); + /* finally, run it */ + wxExecute(Command); } void libmngrFrame::OnQuit(wxCommandEvent& /*event*/) { - Close(true); + Close(true); } void libmngrFrame::ToggleMode(bool symbolmode) { - SymbolMode = symbolmode; - m_toolBar->ToggleTool(IDT_3DVIEW, false); - - /* hide or show the fields in the side panel */ - wxBoxSizer* bsizer; - wxFlexGridSizer* fgSidePanel = dynamic_cast(m_panelSettings->GetSizer()); - wxASSERT(fgSidePanel != 0); - fgSidePanel->Show(m_lblFootprintFilter, SymbolMode); - fgSidePanel->Show(m_txtFootprintFilter, SymbolMode); - fgSidePanel->Show(m_lblPinNames, SymbolMode); - fgSidePanel->Show(m_gridPinNames, SymbolMode); - - fgSidePanel->Show(m_lblPadShape, !SymbolMode); - fgSidePanel->Show(m_choicePadShape, !SymbolMode); - fgSidePanel->Show(m_lblPadSize, !SymbolMode); - bsizer = dynamic_cast(m_txtPadWidth->GetContainingSizer()); - wxASSERT(bsizer != 0); - fgSidePanel->Show(bsizer, !SymbolMode, true); - fgSidePanel->Show(m_lblPitch, !SymbolMode); - fgSidePanel->Show(m_txtPitch, !SymbolMode); - fgSidePanel->Show(m_lblPadSpan, !SymbolMode); - bsizer = dynamic_cast(m_txtPadSpanX->GetContainingSizer()); - wxASSERT(bsizer != 0); - fgSidePanel->Show(bsizer, !SymbolMode, true); - fgSidePanel->Show(m_lblDrillSize, !SymbolMode); - fgSidePanel->Show(m_txtDrillSize, !SymbolMode); - fgSidePanel->Show(m_lblAuxPad, !SymbolMode); - bsizer = dynamic_cast(m_txtAuxPadWidth->GetContainingSizer()); - wxASSERT(bsizer != 0); - fgSidePanel->Show(bsizer, !SymbolMode, true); + SymbolMode = symbolmode; + m_toolBar->ToggleTool(IDT_3DVIEW, false); + + /* hide or show the fields in the side panel */ + wxBoxSizer* bsizer; + wxFlexGridSizer* fgSidePanel = dynamic_cast(m_panelSettings->GetSizer()); + wxASSERT(fgSidePanel != 0); + fgSidePanel->Show(m_lblFootprintFilter, SymbolMode); + fgSidePanel->Show(m_txtFootprintFilter, SymbolMode); + fgSidePanel->Show(m_lblPinNames, SymbolMode); + fgSidePanel->Show(m_gridPinNames, SymbolMode); + + fgSidePanel->Show(m_lblPadShape, !SymbolMode); + fgSidePanel->Show(m_choicePadShape, !SymbolMode); + fgSidePanel->Show(m_lblPadSize, !SymbolMode); + bsizer = dynamic_cast(m_txtPadWidth->GetContainingSizer()); + wxASSERT(bsizer != 0); + fgSidePanel->Show(bsizer, !SymbolMode, true); + fgSidePanel->Show(m_lblPitch, !SymbolMode); + fgSidePanel->Show(m_txtPitch, !SymbolMode); + fgSidePanel->Show(m_lblPadSpan, !SymbolMode); + bsizer = dynamic_cast(m_txtPadSpanX->GetContainingSizer()); + wxASSERT(bsizer != 0); + fgSidePanel->Show(bsizer, !SymbolMode, true); + fgSidePanel->Show(m_lblDrillSize, !SymbolMode); + fgSidePanel->Show(m_txtDrillSize, !SymbolMode); + fgSidePanel->Show(m_lblAuxPad, !SymbolMode); + bsizer = dynamic_cast(m_txtAuxPadWidth->GetContainingSizer()); + wxASSERT(bsizer != 0); + fgSidePanel->Show(bsizer, !SymbolMode, true); fgSidePanel->Show(m_lblShape, !SymbolMode); - bsizer = dynamic_cast(m_choiceShape->GetContainingSizer()); - wxASSERT(bsizer != 0); - fgSidePanel->Show(bsizer, !SymbolMode, true); + bsizer = dynamic_cast(m_choiceShape->GetContainingSizer()); + wxASSERT(bsizer != 0); + fgSidePanel->Show(bsizer, !SymbolMode, true); fgSidePanel->Layout(); - m_panelSettings->Refresh(); + m_panelSettings->Refresh(); /* the "keywords" field for footprints is used for aliases in symbol mode */ - if (SymbolMode) - m_lblAlias->SetLabel(wxT("Alias")); - else - m_lblAlias->SetLabel(wxT("Keywords")); - - /* "pins" is for symbols what "pads" is for footprints */ - if (SymbolMode) - m_lblPadCount->SetLabel(wxT("Pin count")); - else - m_lblPadCount->SetLabel(wxT("Pad count")); - - /* disable options not relevant for schematic mode, or re-enable them */ - m_menubar->Enable(IDM_NEWFOOTPRINT, !SymbolMode); - m_menubar->Enable(IDM_NEWSYMBOL, SymbolMode); - m_menubar->Enable(IDM_REPORTFOOTPRINT, !SymbolMode); - m_menubar->Enable(IDM_REPORTSYMBOL, SymbolMode); - m_toolBar->EnableTool(IDT_MEASUREMENTS, !SymbolMode); + if (SymbolMode) + m_lblAlias->SetLabel(wxT("Alias")); + else + m_lblAlias->SetLabel(wxT("Keywords")); + + /* "pins" is for symbols what "pads" is for footprints */ + if (SymbolMode) + m_lblPadCount->SetLabel(wxT("Pin count")); + else + m_lblPadCount->SetLabel(wxT("Pad count")); + + /* disable options not relevant for schematic mode, or re-enable them */ + m_menubar->Enable(IDM_NEWFOOTPRINT, !SymbolMode); + m_menubar->Enable(IDM_NEWSYMBOL, SymbolMode); + m_menubar->Enable(IDM_REPORTFOOTPRINT, !SymbolMode); + m_menubar->Enable(IDM_REPORTSYMBOL, SymbolMode); + m_toolBar->EnableTool(IDT_MEASUREMENTS, !SymbolMode); m_toolBar->Refresh(); - /* use a different background colour for both modes */ - if (SymbolMode) - m_panelView->SetBackgroundColour(clrSchematicMode); + /* use a different background colour for both modes */ + if (SymbolMode) + m_panelView->SetBackgroundColour(clrSchematicMode); else - m_panelView->SetBackgroundColour(clrFootprintMode); + m_panelView->SetBackgroundColour(clrFootprintMode); - /* restore starting state, and refresh */ - OffsetX = OffsetY = 0; - EnableButtons(0); - CollectAllLibraries(); + /* restore starting state, and refresh */ + OffsetX = OffsetY = 0; + EnableButtons(0); + CollectAllLibraries(); if (ReloadSession) { - wxFileConfig *config = new wxFileConfig(APP_NAME, VENDOR_NAME, theApp->GetINIPath()); - wxString name = config->Read(wxT("session/lib1"), wxEmptyString); + wxFileConfig *config = new wxFileConfig(APP_NAME, VENDOR_NAME, theApp->GetINIPath()); + wxString name = config->Read(wxT("session/lib1"), wxEmptyString); int idx = m_choiceModuleLeft->FindString(name); - if (idx >= 0) + if (idx >= 0) m_choiceModuleLeft->SetSelection(idx); - name = config->Read(wxT("session/lib2"), wxEmptyString); + name = config->Read(wxT("session/lib2"), wxEmptyString); idx = m_choiceModuleRight->FindString(name); - if (idx >= 0) + if (idx >= 0) m_choiceModuleRight->SetSelection(idx); - delete config; + delete config; HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, LEFTPANEL); HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, RIGHTPANEL); Raise(); ReloadSession = false; } - UpdateDetails(0); - m_panelView->Refresh(); + UpdateDetails(0); + m_panelView->Refresh(); } void libmngrFrame::OnFootprintMode(wxCommandEvent& event) { - ToggleMode(false); - event.Skip(); + ToggleMode(false); + event.Skip(); } void libmngrFrame::OnSymbolMode(wxCommandEvent& event) { - ToggleMode(true); - event.Skip(); + ToggleMode(true); + event.Skip(); } void libmngrFrame::OnSearchPaths(wxCommandEvent& /*event*/) { - libmngrDlgPaths dlg(this); - if (dlg.ShowModal() == wxID_OK) { - m_statusBar->SetStatusText(wxT("Settings changed")); - CollectAllLibraries(); - } + libmngrDlgPaths dlg(this); + if (dlg.ShowModal() == wxID_OK) { + m_statusBar->SetStatusText(wxT("Settings changed")); + CollectAllLibraries(); + } } void libmngrFrame::OnRemoteLink(wxCommandEvent& /*event*/) { - #if !defined NO_CURL - libmngrDlgRemoteLink dlg(this); - if (dlg.ShowModal() == wxID_OK) { - m_statusBar->SetStatusText(wxT("Settings changed")); - CollectAllLibraries(); - } - #endif + #if !defined NO_CURL + libmngrDlgRemoteLink dlg(this); + if (dlg.ShowModal() == wxID_OK) { + m_statusBar->SetStatusText(wxT("Settings changed")); + CollectAllLibraries(); + } + #endif } void libmngrFrame::OnReportSettings(wxCommandEvent& /*event*/) { - libmngrDlgReport dlg(this); - if (dlg.ShowModal() == wxID_OK) - m_statusBar->SetStatusText(wxT("Settings changed")); + libmngrDlgReport dlg(this); + if (dlg.ShowModal() == wxID_OK) + m_statusBar->SetStatusText(wxT("Settings changed")); } void libmngrFrame::OnUIOptions(wxCommandEvent& /*event*/) { - libmngrDlgOptions dlg(this); - if (dlg.ShowModal() == wxID_OK) { - m_statusBar->SetStatusText(wxT("Settings changed")); - /* refresh, with the new settings */ - wxFileConfig *config = new wxFileConfig(APP_NAME, VENDOR_NAME, theApp->GetINIPath()); - FontSizeLegend = config->Read(wxT("display/fontsize"), 8L); - DimensionOffset = config->Read(wxT("display/dimoffset"), 50L); - config->Read(wxT("display/footprintbkgnd"), &clrFootprintMode, wxColour(0, 0, 0)); - config->Read(wxT("display/schematicbkgnd"), &clrSchematicMode, wxColour(255, 255, 255)); - config->Read(wxT("display/3dmodelbkgnd"), &clr3DModelMode, wxColour(0, 64, 0)); - config->Read(wxT("display/showlabels"), &ShowLabels, true); - config->Read(wxT("display/centrecross"), &DrawCentreCross, true); - config->Read(wxT("display/fullpath"), &ShowFullPaths, false); - config->Read(wxT("settings/copyvrml"), &CopyVRML, true); - config->Read(wxT("settings/disabletemplate"), &DontRebuildTemplate, false); - config->Read(wxT("settings/confirmoverwrite"), &ConfirmOverwrite, true); - config->Read(wxT("settings/confirmdelete"), &ConfirmDelete, true); - config->Read(wxT("settings/reloadsession"), &ReloadSession, true); - delete config; - - if (SymbolMode) - m_panelView->SetBackgroundColour(clrSchematicMode); + libmngrDlgOptions dlg(this); + if (dlg.ShowModal() == wxID_OK) { + m_statusBar->SetStatusText(wxT("Settings changed")); + /* refresh, with the new settings */ + wxFileConfig *config = new wxFileConfig(APP_NAME, VENDOR_NAME, theApp->GetINIPath()); + FontSizeLegend = config->Read(wxT("display/fontsize"), 8L); + DimensionOffset = config->Read(wxT("display/dimoffset"), 50L); + config->Read(wxT("display/footprintbkgnd"), &clrFootprintMode, wxColour(0, 0, 0)); + config->Read(wxT("display/schematicbkgnd"), &clrSchematicMode, wxColour(255, 255, 255)); + config->Read(wxT("display/3dmodelbkgnd"), &clr3DModelMode, wxColour(0, 64, 0)); + config->Read(wxT("display/showlabels"), &ShowLabels, true); + config->Read(wxT("display/centrecross"), &DrawCentreCross, true); + config->Read(wxT("display/fullpath"), &ShowFullPaths, false); + config->Read(wxT("settings/copyvrml"), &CopyVRML, true); + config->Read(wxT("settings/disabletemplate"), &DontRebuildTemplate, false); + config->Read(wxT("settings/confirmoverwrite"), &ConfirmOverwrite, true); + config->Read(wxT("settings/confirmdelete"), &ConfirmDelete, true); + config->Read(wxT("settings/reloadsession"), &ReloadSession, true); + delete config; + + if (SymbolMode) + m_panelView->SetBackgroundColour(clrSchematicMode); else - m_panelView->SetBackgroundColour(clrFootprintMode); - m_panelView->Refresh(); - } + m_panelView->SetBackgroundColour(clrFootprintMode); + m_panelView->Refresh(); + } } void libmngrFrame::OnTemplateOptions(wxCommandEvent& /*event*/) { - libmngrDlgTemplateOpts dlg(this); - if (dlg.ShowModal() == wxID_OK) - m_statusBar->SetStatusText(wxT("Settings changed")); + libmngrDlgTemplateOpts dlg(this); + if (dlg.ShowModal() == wxID_OK) + m_statusBar->SetStatusText(wxT("Settings changed")); } void libmngrFrame::OnCompareMode(wxCommandEvent& /*event*/) { - CheckSavePart(); - wxBusyCursor cursor; - CompareMode = m_menubar->IsChecked(IDM_COMPAREMODE); - m_toolBar->EnableTool(IDT_LEFTFOOTPRINT, CompareMode); - m_toolBar->EnableTool(IDT_RIGHTFOOTPRINT, CompareMode); - m_toolBar->ToggleTool(IDT_LEFTFOOTPRINT, CompareMode); - m_toolBar->ToggleTool(IDT_RIGHTFOOTPRINT, CompareMode); + CheckSavePart(); + wxBusyCursor cursor; + CompareMode = m_menubar->IsChecked(IDM_COMPAREMODE); + m_toolBar->EnableTool(IDT_LEFTFOOTPRINT, CompareMode); + m_toolBar->EnableTool(IDT_RIGHTFOOTPRINT, CompareMode); + m_toolBar->ToggleTool(IDT_LEFTFOOTPRINT, CompareMode); + m_toolBar->ToggleTool(IDT_RIGHTFOOTPRINT, CompareMode); m_toolBar->Refresh(); - m_radioViewLeft->Enable(CompareMode); - m_radioViewRight->Enable(CompareMode); - m_radioViewLeft->SetValue(true); - - /* disable 3D model mode (if set) */ - if (ModelMode) { - ModelMode = false; - m_toolBar->ToggleTool(IDT_3DVIEW, ModelMode); + m_radioViewLeft->Enable(CompareMode); + m_radioViewRight->Enable(CompareMode); + m_radioViewLeft->SetValue(true); + + /* disable 3D model mode (if set) */ + if (ModelMode) { + ModelMode = false; + m_toolBar->ToggleTool(IDT_3DVIEW, ModelMode); #if !defined NO_3DMODEL sceneGraph.clear(); #endif - } - - if (CompareMode) { - EnableButtons(0); - /* reload the footprints, for both listboxes */ - long idx = m_listModulesLeft->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - if (idx >= 0) - LoadPart(idx, m_listModulesLeft, m_choiceModuleLeft, 0); - idx = m_listModulesRight->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - if (idx >= 0) - LoadPart(idx, m_listModulesRight, m_choiceModuleRight, 1); - } else { - /* remove the selection in the right listctrl (we only keep the left footprint) */ - RemoveSelection(m_listModulesRight, &SelectedPartRight); - PartData[1].Clear(); - /* check whether there is a selection in the left listctrl, only enable - the buttons if so */ - long idx = m_listModulesRight->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - if (idx >= 0) - EnableButtons(LEFTPANEL); - m_radioViewLeft->SetValue(true); - m_radioViewRight->SetValue(false); - } - - OffsetX = OffsetY = 0; - UpdateDetails(0); /* update details for the left component */ - m_panelView->Refresh(); + } + + if (CompareMode) { + EnableButtons(0); + /* reload the footprints, for both listboxes */ + long idx = m_listModulesLeft->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (idx >= 0) + LoadPart(idx, m_listModulesLeft, m_choiceModuleLeft, 0); + idx = m_listModulesRight->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (idx >= 0) + LoadPart(idx, m_listModulesRight, m_choiceModuleRight, 1); + } else { + /* remove the selection in the right listctrl (we only keep the left footprint) */ + RemoveSelection(m_listModulesRight, &SelectedPartRight); + PartData[1].Clear(); + /* check whether there is a selection in the left listctrl, only enable + the buttons if so */ + long idx = m_listModulesRight->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (idx >= 0) + EnableButtons(LEFTPANEL); + m_radioViewLeft->SetValue(true); + m_radioViewRight->SetValue(false); + } + + OffsetX = OffsetY = 0; + UpdateDetails(0); /* update details for the left component */ + m_panelView->Refresh(); } void libmngrFrame::OnDetailsPanel(wxCommandEvent& /*event*/) { - bool details = m_menubar->IsChecked(IDM_DETAILSPANEL); - m_toolBar->ToggleTool(IDT_DETAILSPANEL, details); - ToggleDetailsPanel(details); + bool details = m_menubar->IsChecked(IDM_DETAILSPANEL); + m_toolBar->ToggleTool(IDT_DETAILSPANEL, details); + ToggleDetailsPanel(details); } void libmngrFrame::OnSyncMode(wxCommandEvent& /*event*/) { - CheckSavePart(); - wxBusyCursor cursor; - SyncMode = m_menubar->IsChecked(IDM_SYNCMODE); - /* keep selections in both footprints */ - long selLeft = m_listModulesLeft->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - long selRight = m_listModulesRight->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - /* reload the module lists, for both listboxes */ - HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, BOTHPANELS); - HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, BOTHPANELS); - SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); - /* restore selections */ - if (SyncMode) { - long sel = (selLeft < 0) ? selRight : selLeft; - if (sel >= 0) { - m_listModulesLeft->SetItemState(selLeft, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED); - m_listModulesRight->SetItemState(selRight, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED); - m_listModulesLeft->EnsureVisible(selLeft); - m_listModulesRight->EnsureVisible(selRight); - } - } else { - if (selLeft >= 0) { - m_listModulesLeft->SetItemState(selLeft, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED); - m_listModulesLeft->EnsureVisible(selLeft); - } - if (selRight >= 0) { - m_listModulesRight->SetItemState(selRight, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED); - m_listModulesRight->EnsureVisible(selRight); - } - } - m_panelView->Refresh(); + CheckSavePart(); + wxBusyCursor cursor; + SyncMode = m_menubar->IsChecked(IDM_SYNCMODE); + /* keep selections in both footprints */ + long selLeft = m_listModulesLeft->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + long selRight = m_listModulesRight->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + /* reload the module lists, for both listboxes */ + HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, BOTHPANELS); + HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, BOTHPANELS); + SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); + /* restore selections */ + if (SyncMode) { + long sel = (selLeft < 0) ? selRight : selLeft; + if (sel >= 0) { + m_listModulesLeft->SetItemState(selLeft, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED); + m_listModulesRight->SetItemState(selRight, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED); + m_listModulesLeft->EnsureVisible(selLeft); + m_listModulesRight->EnsureVisible(selRight); + } + } else { + if (selLeft >= 0) { + m_listModulesLeft->SetItemState(selLeft, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED); + m_listModulesLeft->EnsureVisible(selLeft); + } + if (selRight >= 0) { + m_listModulesRight->SetItemState(selRight, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED); + m_listModulesRight->EnsureVisible(selRight); + } + } + m_panelView->Refresh(); } void libmngrFrame::OnFilterToggle(wxCommandEvent& /*event*/) { - if (m_editFilter->IsShown() && m_editFilter->HasFocus()) { - wxString filter = m_editFilter->GetValue(); - m_editFilter->SetValue(wxEmptyString); /* clear the filter */ - m_editFilter->Hide(); - if (filter.Length() > 0 || FilterChanged) { - HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, BOTHPANELS); - HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, BOTHPANELS); - SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); - m_panelView->Refresh(); - } + if (m_editFilter->IsShown() && m_editFilter->HasFocus()) { + wxString filter = m_editFilter->GetValue(); + m_editFilter->SetValue(wxEmptyString); /* clear the filter */ + m_editFilter->Hide(); + if (filter.Length() > 0 || FilterChanged) { + HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, BOTHPANELS); + HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, BOTHPANELS); + SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); + m_panelView->Refresh(); + } } else if (m_editFilter->IsShown()) { m_editFilter->SetSelection(-1, -1); - m_editFilter->SetFocus(); - } else { - m_editFilter->SetValue(wxEmptyString); /* should already be empty */ - m_editFilter->SetBackgroundColour(ENABLED); - m_editFilter->Show(); - m_editFilter->SetFocus(); - } - m_menubar->Check(IDM_FILTER, m_editFilter->IsShown()); - FilterChanged = false; + m_editFilter->SetFocus(); + } else { + m_editFilter->SetValue(wxEmptyString); /* should already be empty */ + m_editFilter->SetBackgroundColour(ENABLED); + m_editFilter->Show(); + m_editFilter->SetFocus(); + } + m_menubar->Check(IDM_FILTER, m_editFilter->IsShown()); + FilterChanged = false; } void libmngrFrame::OnStatusBarDblClk(wxMouseEvent& event) { - /* check whether the click is in the second field */ - wxRect rect; - m_statusBar->GetFieldRect(1, rect); - if (rect.Contains(event.GetX(), event.GetY()) && !m_editFilter->IsShown()) { - m_editFilter->SetValue(wxEmptyString); /* should already be empty */ - m_editFilter->SetBackgroundColour(ENABLED); - m_editFilter->Show(); - m_editFilter->SetFocus(); - FilterChanged = false; - m_menubar->Check(IDM_FILTER, true); - } + /* check whether the click is in the second field */ + wxRect rect; + m_statusBar->GetFieldRect(1, rect); + if (rect.Contains(event.GetX(), event.GetY()) && !m_editFilter->IsShown()) { + m_editFilter->SetValue(wxEmptyString); /* should already be empty */ + m_editFilter->SetBackgroundColour(ENABLED); + m_editFilter->Show(); + m_editFilter->SetFocus(); + FilterChanged = false; + m_menubar->Check(IDM_FILTER, true); + } } void libmngrFrame::OnFilterChange(wxCommandEvent& event) { - if (!FilterChanged) { - m_editFilter->SetBackgroundColour(CHANGED); - m_editFilter->Refresh(); - FilterChanged = true; - } - event.Skip(); + if (!FilterChanged) { + m_editFilter->SetBackgroundColour(CHANGED); + m_editFilter->Refresh(); + FilterChanged = true; + } + event.Skip(); } void libmngrFrame::OnFilterEnter(wxCommandEvent& /*event*/) { - if (FilterChanged) { - HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, BOTHPANELS); - HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, BOTHPANELS); - SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); - m_panelView->Refresh(); - m_editFilter->SetBackgroundColour(ENABLED); - /* check whether the filter must be hidden */ - wxString filter = m_editFilter->GetValue(); - if (filter.Length() > 0) - m_editFilter->Refresh(); - else - m_editFilter->Hide(); - FilterChanged = false; - } + if (FilterChanged) { + HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, BOTHPANELS); + HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, BOTHPANELS); + SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); + m_panelView->Refresh(); + m_editFilter->SetBackgroundColour(ENABLED); + /* check whether the filter must be hidden */ + wxString filter = m_editFilter->GetValue(); + if (filter.Length() > 0) + m_editFilter->Refresh(); + else + m_editFilter->Hide(); + FilterChanged = false; + } } void libmngrFrame::OnFilterCancel(wxCommandEvent& /*event*/) { - wxString filter = m_editFilter->GetValue(); - m_editFilter->SetValue(wxEmptyString); /* clear the filter */ - m_editFilter->Hide(); - if (filter.Length() > 0 || FilterChanged) { - HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, BOTHPANELS); - HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, BOTHPANELS); - SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); - m_panelView->Refresh(); - } + wxString filter = m_editFilter->GetValue(); + m_editFilter->SetValue(wxEmptyString); /* clear the filter */ + m_editFilter->Hide(); + if (filter.Length() > 0 || FilterChanged) { + HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, BOTHPANELS); + HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, BOTHPANELS); + SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); + m_panelView->Refresh(); + } } void libmngrFrame::OnHelp(wxCommandEvent& /*event*/) { - wxString filename = theApp->GetDocumentationPath() + wxT(DIRSEP_STR) wxT("kicadlibrarian.pdf"); - #if wxMAJOR_VERSION < 3 - wxTheMimeTypesManager->ReadMailcap(wxT("/etc/mailcap")); - #endif - wxFileType *FileType = wxTheMimeTypesManager->GetFileTypeFromMimeType(wxT("application/pdf")); - wxString Command = FileType->GetOpenCommand(filename); - if (Command.Find(wxT('*')) > 0) - Command = Command.BeforeFirst(wxT('*')); - Command.Trim(); - wxExecute(Command); + wxString filename = theApp->GetDocumentationPath() + wxT(DIRSEP_STR) wxT("kicadlibrarian.pdf"); + #if wxMAJOR_VERSION < 3 + wxTheMimeTypesManager->ReadMailcap(wxT("/etc/mailcap")); + #endif + wxFileType *FileType = wxTheMimeTypesManager->GetFileTypeFromMimeType(wxT("application/pdf")); + wxString Command = FileType->GetOpenCommand(filename); + if (Command.Find(wxT('*')) > 0) + Command = Command.BeforeFirst(wxT('*')); + Command.Trim(); + wxExecute(Command); } void libmngrFrame::OnAbout(wxCommandEvent& /*event*/) { - wxIcon icon(logo64_xpm); - wxString description = wxT("A utility to view and manage footprint and symbol libraries.\n"); - #if defined NO_CURL - description += wxT("Built without support for remote repositories."); - #else - description += wxT("Including support for remote repositories."); - #endif - - wxAboutDialogInfo info; - info.SetName(wxT("KiCad Librarian")); - info.SetVersion(wxT(SVN_REVSTR)); - info.SetDescription(description); - info.SetCopyright(wxT("(C) 2013-2017 ITB CompuPhase")); - info.SetIcon(icon); - info.SetWebSite(wxT("http://www.compuphase.com/")); - info.AddArtist(wxT("The logo of KiCad Librarian is designed by http://icons8.com/")); - info.AddDeveloper(wxT("KiCad Librarian uses Haru PDF for the reports, Curl to access a remote repository, UnQlite for a cache for filtering and the wxWidgets GUI library")); - wxAboutBox(info); + wxIcon icon(logo64_xpm); + wxString description = wxT("A utility to view and manage footprint and symbol libraries.\n"); + #if defined NO_CURL + description += wxT("Built without support for remote repositories."); + #else + description += wxT("Including support for remote repositories."); + #endif + + wxAboutDialogInfo info; + info.SetName(wxT("KiCad Librarian")); + info.SetVersion(wxT(SVN_REVSTR)); + info.SetDescription(description); + info.SetCopyright(wxT("(C) 2013-2017 ITB CompuPhase")); + info.SetIcon(icon); + info.SetWebSite(wxT("http://www.compuphase.com/")); + info.AddArtist(wxT("The logo of KiCad Librarian is designed by http://icons8.com/")); + info.AddDeveloper(wxT("KiCad Librarian uses Haru PDF for the reports, Curl to access a remote repository, UnQlite for a cache for filtering and the wxWidgets GUI library")); + wxAboutBox(info); } void libmngrFrame::OnMovePart(wxCommandEvent& /*event*/) { - wxString modname, source, target, author; - wxString leftmod = GetSelection(m_listModulesLeft, m_choiceModuleLeft, &source, &author); - wxString rightmod = GetSelection(m_listModulesRight, m_choiceModuleRight, &source, &author); - wxASSERT(leftmod.IsEmpty() || rightmod.IsEmpty()); - - wxListCtrl* tgtlist = NULL; - int syncdir = 0; - if (leftmod.length() > 0) { - modname = leftmod; - long idx = m_choiceModuleRight->GetCurrentSelection(); - wxASSERT(idx >= 0 && idx < (long)m_choiceModuleRight->GetCount()); - target = m_choiceModuleRight->GetString(idx); - tgtlist = m_listModulesRight; - syncdir = LEFTPANEL; - } else if (rightmod.length() > 0) { - modname = rightmod; - long idx = m_choiceModuleLeft->GetCurrentSelection(); - wxASSERT(idx >= 0 && idx < (long)m_choiceModuleLeft->GetCount()); - target = m_choiceModuleLeft->GetString(idx); - tgtlist = m_listModulesLeft; - syncdir = RIGHTPANEL; - } - if (source.length() == 0 || target.length() == 0) { - wxASSERT(SyncMode); - wxMessageBox(wxT("This part does not exist.")); - return; - } - wxASSERT(source.length() > 0); - wxASSERT(target.length() > 0); - - if (SymbolMode) { - /* first remove the symbol from the target library (if it exists) */ - if (ExistSymbol(target, modname)) { - if (ConfirmOverwrite - && wxMessageBox(wxT("Overwrite \"") + modname + wxT("\"\nin ") + target + wxT("?"), wxT("Confirm overwrite"), wxYES_NO | wxICON_QUESTION) != wxYES) - return; - RemoveSymbol(target, modname); - } - - wxASSERT(PartData[0].Count() > 0); - if (InsertSymbol(target, modname, PartData[0])) { - RemoveSymbol(source, modname); - if (target.CmpNoCase(LIB_REPOS) == 0) { - wxString preview = ExportSymbolBitmap(modname); - StoreSymbolInfo(modname, GetDescription(PartData[0], true), - GetKeywords(PartData[0], true), GetAliases(PartData[0]), - GetFootprints(PartData[0]), preview); - wxRemoveFile(preview); - } - /* both libraries need to be refreshed */ - HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, BOTHPANELS); - HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, BOTHPANELS); - SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); - /* find the item in the target list, to scroll to that position */ - wxASSERT(tgtlist != NULL); - long idx = tgtlist->FindItem(-1, modname); - if (idx >= 0) - tgtlist->EnsureVisible(idx); - SyncScroll(syncdir); - m_panelView->Refresh(); - } else { - wxMessageBox(wxT("Operation failed.")); - } - } else { - /* get the types of the libraries (and check) */ - int sourcetype = LibraryType(source); - int targettype = LibraryType(target); - if (sourcetype == VER_INVALID) { - wxMessageBox(wxT("Unsupported file format for the source library.")); - return; - } else if (targettype == VER_INVALID) { - wxMessageBox(wxT("Unsupported file format for the target library.")); - return; - } - /* also check whether the target is an export file (instead of a library) */ - if (target.Right(10).Cmp(wxT(".kicad_mod")) == 0 || target.Right(4).Cmp(wxT(".emp")) == 0) { - wxMessageBox(wxT("The target file is an export file instead of a library.\nFootprints cannot be added to export files.")); - return; - } - - if (ConfirmOverwrite - && ExistFootprint(target, modname) - && wxMessageBox(wxT("Overwrite \"") + modname + wxT("\"\nin ") + target + wxT("?"), wxT("Confirm overwrite"), wxYES_NO | wxICON_QUESTION) != wxYES) - return; - - if (sourcetype == VER_S_EXPR && targettype == VER_S_EXPR) { - /* create full names for source and target, then move the file */ - wxFileName old_fname(source, modname + wxT(".kicad_mod")); - wxFileName new_fname(target, modname + wxT(".kicad_mod")); - if (source.Right(10).Cmp(wxT(".kicad_mod")) == 0) - old_fname = wxFileName(source); - if (wxRenameFile(old_fname.GetFullPath(), new_fname.GetFullPath(), true)) { - HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, BOTHPANELS); - HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, BOTHPANELS); - SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); - /* find the item in the target list, to scroll to that position */ - wxASSERT(tgtlist != NULL); - long idx = tgtlist->FindItem(-1, modname); - if (idx >= 0) - tgtlist->EnsureVisible(idx); - SyncScroll(syncdir); - m_panelView->Refresh(); - } else { - wxMessageBox(wxT("Operation failed.")); - } - } else { - /* make a copy of the name, because the user may need to adjust it */ - wxString newname = modname; - wxArrayString sourcedata; /* create a copy, to avoid converting the original */ - if (sourcetype == VER_S_EXPR) { - wxASSERT(targettype != VER_S_EXPR); - TranslateToLegacy(&sourcedata, PartData[0]); - sourcetype = VER_MM; - } else if (targettype == VER_S_EXPR) { - wxASSERT(sourcetype != VER_S_EXPR); - wxArrayString data_mm = PartData[0]; - if (sourcetype == VER_MIL) - TranslateUnits(data_mm, false, true); - TranslateToSexpr(&sourcedata, data_mm); - sourcetype = VER_S_EXPR; - /* verify that the name is valid */ - if (!ValidateFilename(&newname)) - return; - } else { - wxASSERT(sourcetype != VER_S_EXPR && targettype != VER_S_EXPR); - sourcedata = PartData[0]; - } - RemoveFootprint(target, newname); /* remove the footprint from the target library */ - wxASSERT(sourcedata.Count() > 0); - if (InsertFootprint(target, newname, sourcedata, sourcetype >= VER_MM)) { - RemoveFootprint(source, modname); - if (target.CmpNoCase(LIB_REPOS) == 0) { - double span = 0; - if (Footprint[0].SpanHor <= EPSILON) - span = Footprint[0].SpanVer; - else if (Footprint[0].SpanVer <= EPSILON) - span = Footprint[0].SpanHor; - else - span = Footprint[0].PitchVertical ? Footprint[0].SpanHor : Footprint[0].SpanVer; - wxString preview = ExportFootprintBitmap(modname); - StoreFootprintInfo(modname, GetDescription(sourcedata, false), GetKeywords(PartData[0], false), - Footprint[0].Pitch, span, Footprint[0].PadCount, preview); - wxRemoveFile(preview); - } - /* both libraries need to be refreshed */ - HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, BOTHPANELS); - HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, BOTHPANELS); - SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); - /* find the item in the target list, to scroll to that position */ - wxASSERT(tgtlist != NULL); - long idx = tgtlist->FindItem(-1, modname); - if (idx >= 0) - tgtlist->EnsureVisible(idx); - SyncScroll(syncdir); - m_panelView->Refresh(); - } else { - wxMessageBox(wxT("Operation failed.")); - } - } - if (CopyVRML) - CopyVRMLfile(source, target, author, PartData[0]); - } + wxString modname, source, target, author; + wxString leftmod = GetSelection(m_listModulesLeft, m_choiceModuleLeft, &source, &author); + wxString rightmod = GetSelection(m_listModulesRight, m_choiceModuleRight, &source, &author); + wxASSERT(leftmod.IsEmpty() || rightmod.IsEmpty()); + + wxListCtrl* tgtlist = NULL; + int syncdir = 0; + if (leftmod.length() > 0) { + modname = leftmod; + long idx = m_choiceModuleRight->GetCurrentSelection(); + wxASSERT(idx >= 0 && idx < (long)m_choiceModuleRight->GetCount()); + target = m_choiceModuleRight->GetString(idx); + tgtlist = m_listModulesRight; + syncdir = LEFTPANEL; + } else if (rightmod.length() > 0) { + modname = rightmod; + long idx = m_choiceModuleLeft->GetCurrentSelection(); + wxASSERT(idx >= 0 && idx < (long)m_choiceModuleLeft->GetCount()); + target = m_choiceModuleLeft->GetString(idx); + tgtlist = m_listModulesLeft; + syncdir = RIGHTPANEL; + } + if (source.length() == 0 || target.length() == 0) { + wxASSERT(SyncMode); + wxMessageBox(wxT("This part does not exist.")); + return; + } + wxASSERT(source.length() > 0); + wxASSERT(target.length() > 0); + + if (SymbolMode) { + /* first remove the symbol from the target library (if it exists) */ + if (ExistSymbol(target, modname)) { + if (ConfirmOverwrite + && wxMessageBox(wxT("Overwrite \"") + modname + wxT("\"\nin ") + target + wxT("?"), wxT("Confirm overwrite"), wxYES_NO | wxICON_QUESTION) != wxYES) + return; + RemoveSymbol(target, modname); + } + + wxASSERT(PartData[0].Count() > 0); + if (InsertSymbol(target, modname, PartData[0])) { + RemoveSymbol(source, modname); + if (target.CmpNoCase(LIB_REPOS) == 0) { + wxString preview = ExportSymbolBitmap(modname); + StoreSymbolInfo(modname, GetDescription(PartData[0], true), + GetKeywords(PartData[0], true), GetAliases(PartData[0]), + GetFootprints(PartData[0]), preview); + wxRemoveFile(preview); + } + /* both libraries need to be refreshed */ + HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, BOTHPANELS); + HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, BOTHPANELS); + SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); + /* find the item in the target list, to scroll to that position */ + wxASSERT(tgtlist != NULL); + long idx = tgtlist->FindItem(-1, modname); + if (idx >= 0) + tgtlist->EnsureVisible(idx); + SyncScroll(syncdir); + m_panelView->Refresh(); + } else { + wxMessageBox(wxT("Operation failed.")); + } + } else { + /* get the types of the libraries (and check) */ + int sourcetype = LibraryType(source); + int targettype = LibraryType(target); + if (sourcetype == VER_INVALID) { + wxMessageBox(wxT("Unsupported file format for the source library.")); + return; + } else if (targettype == VER_INVALID) { + wxMessageBox(wxT("Unsupported file format for the target library.")); + return; + } + /* also check whether the target is an export file (instead of a library) */ + if (target.Right(10).Cmp(wxT(".kicad_mod")) == 0 || target.Right(4).Cmp(wxT(".emp")) == 0) { + wxMessageBox(wxT("The target file is an export file instead of a library.\nFootprints cannot be added to export files.")); + return; + } + + if (ConfirmOverwrite + && ExistFootprint(target, modname) + && wxMessageBox(wxT("Overwrite \"") + modname + wxT("\"\nin ") + target + wxT("?"), wxT("Confirm overwrite"), wxYES_NO | wxICON_QUESTION) != wxYES) + return; + + if (sourcetype == VER_S_EXPR && targettype == VER_S_EXPR) { + /* create full names for source and target, then move the file */ + wxFileName old_fname(source, modname + wxT(".kicad_mod")); + wxFileName new_fname(target, modname + wxT(".kicad_mod")); + if (source.Right(10).Cmp(wxT(".kicad_mod")) == 0) + old_fname = wxFileName(source); + if (wxRenameFile(old_fname.GetFullPath(), new_fname.GetFullPath(), true)) { + HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, BOTHPANELS); + HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, BOTHPANELS); + SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); + /* find the item in the target list, to scroll to that position */ + wxASSERT(tgtlist != NULL); + long idx = tgtlist->FindItem(-1, modname); + if (idx >= 0) + tgtlist->EnsureVisible(idx); + SyncScroll(syncdir); + m_panelView->Refresh(); + } else { + wxMessageBox(wxT("Operation failed.")); + } + } else { + /* make a copy of the name, because the user may need to adjust it */ + wxString newname = modname; + wxArrayString sourcedata; /* create a copy, to avoid converting the original */ + if (sourcetype == VER_S_EXPR) { + wxASSERT(targettype != VER_S_EXPR); + TranslateToLegacy(&sourcedata, PartData[0]); + sourcetype = VER_MM; + } else if (targettype == VER_S_EXPR) { + wxASSERT(sourcetype != VER_S_EXPR); + wxArrayString data_mm = PartData[0]; + if (sourcetype == VER_MIL) + TranslateUnits(data_mm, false, true); + TranslateToSexpr(&sourcedata, data_mm); + sourcetype = VER_S_EXPR; + /* verify that the name is valid */ + if (!ValidateFilename(&newname)) + return; + } else { + wxASSERT(sourcetype != VER_S_EXPR && targettype != VER_S_EXPR); + sourcedata = PartData[0]; + } + RemoveFootprint(target, newname); /* remove the footprint from the target library */ + wxASSERT(sourcedata.Count() > 0); + if (InsertFootprint(target, newname, sourcedata, sourcetype >= VER_MM)) { + RemoveFootprint(source, modname); + if (target.CmpNoCase(LIB_REPOS) == 0) { + double span = 0; + if (Footprint[0].SpanHor <= EPSILON) + span = Footprint[0].SpanVer; + else if (Footprint[0].SpanVer <= EPSILON) + span = Footprint[0].SpanHor; + else + span = Footprint[0].PitchVertical ? Footprint[0].SpanHor : Footprint[0].SpanVer; + wxString preview = ExportFootprintBitmap(modname); + StoreFootprintInfo(modname, GetDescription(sourcedata, false), GetKeywords(PartData[0], false), + Footprint[0].Pitch, span, Footprint[0].PadCount, preview); + wxRemoveFile(preview); + } + /* both libraries need to be refreshed */ + HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, BOTHPANELS); + HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, BOTHPANELS); + SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); + /* find the item in the target list, to scroll to that position */ + wxASSERT(tgtlist != NULL); + long idx = tgtlist->FindItem(-1, modname); + if (idx >= 0) + tgtlist->EnsureVisible(idx); + SyncScroll(syncdir); + m_panelView->Refresh(); + } else { + wxMessageBox(wxT("Operation failed.")); + } + } + if (CopyVRML) + CopyVRMLfile(source, target, author, PartData[0]); + } } void libmngrFrame::OnCopyPart(wxCommandEvent& /*event*/) { - wxString modname, source, target, author; - wxString leftmod = GetSelection(m_listModulesLeft, m_choiceModuleLeft, &source, &author); - wxString rightmod = GetSelection(m_listModulesRight, m_choiceModuleRight, &source, &author); - wxASSERT(leftmod.IsEmpty() || rightmod.IsEmpty()); - - int refresh = 0; - if (leftmod.length() > 0) { - modname = leftmod; - refresh = RIGHTPANEL; /* after copy, must refresh the right list */ - long idx = m_choiceModuleRight->GetCurrentSelection(); - wxASSERT(idx >= 0 && idx < (long)m_choiceModuleRight->GetCount()); - target = m_choiceModuleRight->GetString(idx); - } else if (rightmod.length() > 0) { - modname = rightmod; - refresh = LEFTPANEL; /* after copy, must refresh the left list */ - long idx = m_choiceModuleLeft->GetCurrentSelection(); - wxASSERT(idx >= 0 && idx < (long)m_choiceModuleLeft->GetCount()); - target = m_choiceModuleLeft->GetString(idx); - } - if (source.length() == 0 || target.length() == 0) { - wxASSERT(SyncMode); - wxMessageBox(wxT("This part does not exist.")); - return; - } - wxASSERT(source.length() > 0); - wxASSERT(target.length() > 0); - wxASSERT(target.CmpNoCase(LIB_ALL) != 0); - - if (SymbolMode) { - /* first remove the symbol from the target library (if it exists) */ - if (ExistSymbol(target, modname)) { - if (ConfirmOverwrite - && wxMessageBox(wxT("Overwrite \"") + modname + wxT("\"\nin ") + target + wxT("?"), wxT("Confirm overwrite"), wxYES_NO | wxICON_QUESTION) != wxYES) - return; - RemoveSymbol(target, modname); - } - - wxASSERT(PartData[0].Count() > 0); - if (InsertSymbol(target, modname, PartData[0])) { - if (target.CmpNoCase(LIB_REPOS) == 0) { - wxString preview = ExportSymbolBitmap(modname); - StoreSymbolInfo(modname, GetDescription(PartData[0], true), GetKeywords(PartData[0], true), - GetAliases(PartData[0]), GetFootprints(PartData[0]), preview); - wxRemoveFile(preview); - } - if (refresh == LEFTPANEL) - HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, LEFTPANEL); - else if (refresh == RIGHTPANEL) - HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, RIGHTPANEL); - SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); - SyncScroll(refresh); - m_panelView->Refresh(); - } else { - wxMessageBox(wxT("Operation failed.")); - } - } else { - /* get the types of the libraries (and check) */ - int sourcetype = LibraryType(source); - int targettype = LibraryType(target); - if (sourcetype == VER_INVALID) { - wxMessageBox(wxT("Unsupported file format for the source library.")); - return; - } else if (targettype == VER_INVALID) { - wxMessageBox(wxT("Unsupported file format for the target library.")); - return; - } - /* also check whether the target is an export file (instead of a library) */ - if (target.Right(10).Cmp(wxT(".kicad_mod")) == 0 || target.Right(4).Cmp(wxT(".emp")) == 0) { - wxMessageBox(wxT("The target file is an export file instead of a library.\nFootprints cannot be added to export files.")); - return; - } - - if (ConfirmOverwrite - && ExistFootprint(target, modname) - && wxMessageBox(wxT("Overwrite \"") + modname + wxT("\"\nin ") + target + wxT("?"), wxT("Confirm overwrite"), wxYES_NO | wxICON_QUESTION) != wxYES) - return; - - if (sourcetype == VER_S_EXPR && targettype == VER_S_EXPR) { - /* create full names for source and target, then copy the file */ - wxFileName old_fname(source, modname + wxT(".kicad_mod")); - wxFileName new_fname(target, modname + wxT(".kicad_mod")); - if (source.Right(10).Cmp(wxT(".kicad_mod")) == 0) - old_fname = wxFileName(source); - if (wxCopyFile(old_fname.GetFullPath(), new_fname.GetFullPath(), true)) { - if (refresh == LEFTPANEL) - HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, LEFTPANEL); - else if (refresh == RIGHTPANEL) - HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, RIGHTPANEL); - SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); - SyncScroll(refresh); - m_panelView->Refresh(); - } else { - wxMessageBox(wxT("Operation failed.")); - } - } else { - wxArrayString sourcedata; /* create a copy, to avoid converting the original */ - if (sourcetype == VER_S_EXPR) { - wxASSERT(targettype != VER_S_EXPR); - TranslateToLegacy(&sourcedata, PartData[0]); - sourcetype = VER_MM; - } else if (targettype == VER_S_EXPR) { - wxASSERT(sourcetype != VER_S_EXPR); - wxArrayString data_mm = PartData[0]; - if (sourcetype == VER_MIL) - TranslateUnits(data_mm, false, true); - TranslateToSexpr(&sourcedata, data_mm); - sourcetype = VER_S_EXPR; - /* verify that the name is valid */ - if (!ValidateFilename(&modname)) - return; - } else { - wxASSERT(sourcetype != VER_S_EXPR && targettype != VER_S_EXPR); - sourcedata = PartData[0]; - } - RemoveFootprint(target, modname); /* remove the footprint from the target library */ - wxASSERT(sourcedata.Count() > 0); - if (InsertFootprint(target, modname, sourcedata, sourcetype >= VER_MM)) { - if (target.CmpNoCase(LIB_REPOS) == 0) { - double span = 0; - if (Footprint[0].SpanHor <= EPSILON) - span = Footprint[0].SpanVer; - else if (Footprint[0].SpanVer <= EPSILON) - span = Footprint[0].SpanHor; - else - span = Footprint[0].PitchVertical ? Footprint[0].SpanHor : Footprint[0].SpanVer; - wxString preview = ExportFootprintBitmap(modname); - StoreFootprintInfo(modname, GetDescription(sourcedata, false), GetKeywords(PartData[0], false), - Footprint[0].Pitch, span, Footprint[0].PadCount, preview); - wxRemoveFile(preview); - } - if (refresh == LEFTPANEL) - HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, LEFTPANEL); - else if (refresh == RIGHTPANEL) - HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, RIGHTPANEL); - SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); - SyncScroll(refresh); - m_panelView->Refresh(); - } else { - wxMessageBox(wxT("Operation failed.")); - } - } - if (CopyVRML) - CopyVRMLfile(source, target, author, PartData[0]); - } + wxString modname, source, target, author; + wxString leftmod = GetSelection(m_listModulesLeft, m_choiceModuleLeft, &source, &author); + wxString rightmod = GetSelection(m_listModulesRight, m_choiceModuleRight, &source, &author); + wxASSERT(leftmod.IsEmpty() || rightmod.IsEmpty()); + + int refresh = 0; + if (leftmod.length() > 0) { + modname = leftmod; + refresh = RIGHTPANEL; /* after copy, must refresh the right list */ + long idx = m_choiceModuleRight->GetCurrentSelection(); + wxASSERT(idx >= 0 && idx < (long)m_choiceModuleRight->GetCount()); + target = m_choiceModuleRight->GetString(idx); + } else if (rightmod.length() > 0) { + modname = rightmod; + refresh = LEFTPANEL; /* after copy, must refresh the left list */ + long idx = m_choiceModuleLeft->GetCurrentSelection(); + wxASSERT(idx >= 0 && idx < (long)m_choiceModuleLeft->GetCount()); + target = m_choiceModuleLeft->GetString(idx); + } + if (source.length() == 0 || target.length() == 0) { + wxASSERT(SyncMode); + wxMessageBox(wxT("This part does not exist.")); + return; + } + wxASSERT(source.length() > 0); + wxASSERT(target.length() > 0); + wxASSERT(target.CmpNoCase(LIB_ALL) != 0); + + if (SymbolMode) { + /* first remove the symbol from the target library (if it exists) */ + if (ExistSymbol(target, modname)) { + if (ConfirmOverwrite + && wxMessageBox(wxT("Overwrite \"") + modname + wxT("\"\nin ") + target + wxT("?"), wxT("Confirm overwrite"), wxYES_NO | wxICON_QUESTION) != wxYES) + return; + RemoveSymbol(target, modname); + } + + wxASSERT(PartData[0].Count() > 0); + if (InsertSymbol(target, modname, PartData[0])) { + if (target.CmpNoCase(LIB_REPOS) == 0) { + wxString preview = ExportSymbolBitmap(modname); + StoreSymbolInfo(modname, GetDescription(PartData[0], true), GetKeywords(PartData[0], true), + GetAliases(PartData[0]), GetFootprints(PartData[0]), preview); + wxRemoveFile(preview); + } + if (refresh == LEFTPANEL) + HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, LEFTPANEL); + else if (refresh == RIGHTPANEL) + HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, RIGHTPANEL); + SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); + SyncScroll(refresh); + m_panelView->Refresh(); + } else { + wxMessageBox(wxT("Operation failed.")); + } + } else { + /* get the types of the libraries (and check) */ + int sourcetype = LibraryType(source); + int targettype = LibraryType(target); + if (sourcetype == VER_INVALID) { + wxMessageBox(wxT("Unsupported file format for the source library.")); + return; + } else if (targettype == VER_INVALID) { + wxMessageBox(wxT("Unsupported file format for the target library.")); + return; + } + /* also check whether the target is an export file (instead of a library) */ + if (target.Right(10).Cmp(wxT(".kicad_mod")) == 0 || target.Right(4).Cmp(wxT(".emp")) == 0) { + wxMessageBox(wxT("The target file is an export file instead of a library.\nFootprints cannot be added to export files.")); + return; + } + + if (ConfirmOverwrite + && ExistFootprint(target, modname) + && wxMessageBox(wxT("Overwrite \"") + modname + wxT("\"\nin ") + target + wxT("?"), wxT("Confirm overwrite"), wxYES_NO | wxICON_QUESTION) != wxYES) + return; + + if (sourcetype == VER_S_EXPR && targettype == VER_S_EXPR) { + /* create full names for source and target, then copy the file */ + wxFileName old_fname(source, modname + wxT(".kicad_mod")); + wxFileName new_fname(target, modname + wxT(".kicad_mod")); + if (source.Right(10).Cmp(wxT(".kicad_mod")) == 0) + old_fname = wxFileName(source); + if (wxCopyFile(old_fname.GetFullPath(), new_fname.GetFullPath(), true)) { + if (refresh == LEFTPANEL) + HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, LEFTPANEL); + else if (refresh == RIGHTPANEL) + HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, RIGHTPANEL); + SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); + SyncScroll(refresh); + m_panelView->Refresh(); + } else { + wxMessageBox(wxT("Operation failed.")); + } + } else { + wxArrayString sourcedata; /* create a copy, to avoid converting the original */ + if (sourcetype == VER_S_EXPR) { + wxASSERT(targettype != VER_S_EXPR); + TranslateToLegacy(&sourcedata, PartData[0]); + sourcetype = VER_MM; + } else if (targettype == VER_S_EXPR) { + wxASSERT(sourcetype != VER_S_EXPR); + wxArrayString data_mm = PartData[0]; + if (sourcetype == VER_MIL) + TranslateUnits(data_mm, false, true); + TranslateToSexpr(&sourcedata, data_mm); + sourcetype = VER_S_EXPR; + /* verify that the name is valid */ + if (!ValidateFilename(&modname)) + return; + } else { + wxASSERT(sourcetype != VER_S_EXPR && targettype != VER_S_EXPR); + sourcedata = PartData[0]; + } + RemoveFootprint(target, modname); /* remove the footprint from the target library */ + wxASSERT(sourcedata.Count() > 0); + if (InsertFootprint(target, modname, sourcedata, sourcetype >= VER_MM)) { + if (target.CmpNoCase(LIB_REPOS) == 0) { + double span = 0; + if (Footprint[0].SpanHor <= EPSILON) + span = Footprint[0].SpanVer; + else if (Footprint[0].SpanVer <= EPSILON) + span = Footprint[0].SpanHor; + else + span = Footprint[0].PitchVertical ? Footprint[0].SpanHor : Footprint[0].SpanVer; + wxString preview = ExportFootprintBitmap(modname); + StoreFootprintInfo(modname, GetDescription(sourcedata, false), GetKeywords(PartData[0], false), + Footprint[0].Pitch, span, Footprint[0].PadCount, preview); + wxRemoveFile(preview); + } + if (refresh == LEFTPANEL) + HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, LEFTPANEL); + else if (refresh == RIGHTPANEL) + HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, RIGHTPANEL); + SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); + SyncScroll(refresh); + m_panelView->Refresh(); + } else { + wxMessageBox(wxT("Operation failed.")); + } + } + if (CopyVRML) + CopyVRMLfile(source, target, author, PartData[0]); + } } void libmngrFrame::OnDeletePart(wxCommandEvent& /*event*/) { - wxString modname, filename; - wxString leftmod = GetSelection(m_listModulesLeft, m_choiceModuleLeft, &filename); - wxString rightmod = GetSelection(m_listModulesRight, m_choiceModuleRight, &filename); - wxASSERT(leftmod.IsEmpty() || rightmod.IsEmpty()); - - int refresh = 0; - if (leftmod.length() > 0) { - modname = leftmod; - refresh = LEFTPANEL; /* after deletion, must refresh the left list */ - } else if (rightmod.length() > 0) { - modname = rightmod; - refresh = RIGHTPANEL; /* after deletion, must refresh the right list */ - } - - if (filename.length() == 0) { - wxASSERT(SyncMode); - wxMessageBox(wxT("This part does not exist.")); - return; - } - wxASSERT(filename.length() > 0); - - if (!ConfirmDelete || wxMessageBox(wxT("Delete \"") + modname + wxT("\"\nfrom ") + filename + wxT("?"), wxT("Confirm deletion"), wxYES_NO | wxICON_QUESTION) == wxYES) { - bool result; - if (SymbolMode) - result = RemoveSymbol(filename, modname); - else - result = RemoveFootprint(filename, modname); - if (result) { - PartData[0].Clear(); - PartData[1].Clear(); /* should already be clear (delete operation is inactive in compare mode) */ - if (refresh == LEFTPANEL) - HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, LEFTPANEL); - else if (refresh == RIGHTPANEL) - HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, RIGHTPANEL); - SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); - SyncScroll(refresh); - m_panelView->Refresh(); - UpdateDetails(0); - } else { - wxMessageBox(wxT("Operation failed")); - } - } + wxString modname, filename; + wxString leftmod = GetSelection(m_listModulesLeft, m_choiceModuleLeft, &filename); + wxString rightmod = GetSelection(m_listModulesRight, m_choiceModuleRight, &filename); + wxASSERT(leftmod.IsEmpty() || rightmod.IsEmpty()); + + int refresh = 0; + if (leftmod.length() > 0) { + modname = leftmod; + refresh = LEFTPANEL; /* after deletion, must refresh the left list */ + } else if (rightmod.length() > 0) { + modname = rightmod; + refresh = RIGHTPANEL; /* after deletion, must refresh the right list */ + } + + if (filename.length() == 0) { + wxASSERT(SyncMode); + wxMessageBox(wxT("This part does not exist.")); + return; + } + wxASSERT(filename.length() > 0); + + if (!ConfirmDelete || wxMessageBox(wxT("Delete \"") + modname + wxT("\"\nfrom ") + filename + wxT("?"), wxT("Confirm deletion"), wxYES_NO | wxICON_QUESTION) == wxYES) { + bool result; + if (SymbolMode) + result = RemoveSymbol(filename, modname); + else + result = RemoveFootprint(filename, modname); + if (result) { + PartData[0].Clear(); + PartData[1].Clear(); /* should already be clear (delete operation is inactive in compare mode) */ + if (refresh == LEFTPANEL) + HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, LEFTPANEL); + else if (refresh == RIGHTPANEL) + HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, RIGHTPANEL); + SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); + SyncScroll(refresh); + m_panelView->Refresh(); + UpdateDetails(0); + } else { + wxMessageBox(wxT("Operation failed")); + } + } } void libmngrFrame::OnRenamePart(wxCommandEvent& /*event*/) { - wxString modname, filename; - wxString leftmod = GetSelection(m_listModulesLeft, m_choiceModuleLeft, &filename); - wxString rightmod = GetSelection(m_listModulesRight, m_choiceModuleRight, &filename); - wxASSERT(leftmod.IsEmpty() || rightmod.IsEmpty()); - - int refresh = 0; - if (leftmod.length() > 0) { - modname = leftmod; - refresh = LEFTPANEL; /* after rename, must refresh the left list */ - } else if (rightmod.length() > 0) { - modname = rightmod; - refresh = RIGHTPANEL; /* after rename, must refresh the right list */ - } - - if (filename.length() == 0) { - wxASSERT(SyncMode); - wxMessageBox(wxT("This part does not exist.")); - return; - } - wxASSERT(filename.length() > 0); - - wxTextEntryDialog dlg(this, wxT("New name"), wxT("Rename ") + modname, modname); - if (dlg.ShowModal() == wxID_OK) { - wxString newname = dlg.GetValue(); - if (!SymbolMode) { - /* verify that the new name is a valid symbol (in s-expression libraries, - the footprint name is a filename) */ - if (!ValidateFilename(&newname)) - return; - } - if (newname.length() > 0) { - bool result; - if (SymbolMode) - result = RenameSymbol(filename, modname, newname); - else - result = RenameFootprint(filename, modname, newname); - if (result) { - wxASSERT(refresh == LEFTPANEL || refresh == RIGHTPANEL); - wxChoice *choice = (refresh == LEFTPANEL) ? m_choiceModuleLeft : m_choiceModuleRight; - wxListCtrl *list = (refresh == LEFTPANEL) ? m_listModulesLeft : m_listModulesRight; - HandleLibrarySelect(choice, list, refresh); - /* get the index of the new part in the footprint list */ - int idx; - for (idx = 0; idx < list->GetItemCount(); idx++) { - wxString symbol = list->GetItemText(idx); - if (symbol.Cmp(newname) == 0) - break; - } - wxASSERT(idx < list->GetItemCount()); /* it was just renamed, so it must be found */ - list->SetItemState(idx, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED); - list->EnsureVisible(idx); - SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); - SyncScroll(refresh); - m_panelView->Refresh(); - } else { - wxMessageBox(wxT("Operation failed")); - } - } - } + wxString modname, filename; + wxString leftmod = GetSelection(m_listModulesLeft, m_choiceModuleLeft, &filename); + wxString rightmod = GetSelection(m_listModulesRight, m_choiceModuleRight, &filename); + wxASSERT(leftmod.IsEmpty() || rightmod.IsEmpty()); + + int refresh = 0; + if (leftmod.length() > 0) { + modname = leftmod; + refresh = LEFTPANEL; /* after rename, must refresh the left list */ + } else if (rightmod.length() > 0) { + modname = rightmod; + refresh = RIGHTPANEL; /* after rename, must refresh the right list */ + } + + if (filename.length() == 0) { + wxASSERT(SyncMode); + wxMessageBox(wxT("This part does not exist.")); + return; + } + wxASSERT(filename.length() > 0); + + wxTextEntryDialog dlg(this, wxT("New name"), wxT("Rename ") + modname, modname); + if (dlg.ShowModal() == wxID_OK) { + wxString newname = dlg.GetValue(); + if (!SymbolMode) { + /* verify that the new name is a valid symbol (in s-expression libraries, + the footprint name is a filename) */ + if (!ValidateFilename(&newname)) + return; + } + if (newname.length() > 0) { + bool result; + if (SymbolMode) + result = RenameSymbol(filename, modname, newname); + else + result = RenameFootprint(filename, modname, newname); + if (result) { + wxASSERT(refresh == LEFTPANEL || refresh == RIGHTPANEL); + wxChoice *choice = (refresh == LEFTPANEL) ? m_choiceModuleLeft : m_choiceModuleRight; + wxListCtrl *list = (refresh == LEFTPANEL) ? m_listModulesLeft : m_listModulesRight; + HandleLibrarySelect(choice, list, refresh); + /* get the index of the new part in the footprint list */ + int idx; + for (idx = 0; idx < list->GetItemCount(); idx++) { + wxString symbol = list->GetItemText(idx); + if (symbol.Cmp(newname) == 0) + break; + } + wxASSERT(idx < list->GetItemCount()); /* it was just renamed, so it must be found */ + list->SetItemState(idx, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED); + list->EnsureVisible(idx); + SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); + SyncScroll(refresh); + m_panelView->Refresh(); + } else { + wxMessageBox(wxT("Operation failed")); + } + } + } } void libmngrFrame::OnDuplicatePart(wxCommandEvent& /*event*/) { - wxString modname, filename, author; - wxString leftmod = GetSelection(m_listModulesLeft, m_choiceModuleLeft, &filename, &author); - wxString rightmod = GetSelection(m_listModulesRight, m_choiceModuleRight, &filename, &author); - wxASSERT(leftmod.IsEmpty() || rightmod.IsEmpty()); - - int refresh = 0; - if (leftmod.length() > 0) { - modname = leftmod; - refresh = LEFTPANEL; /* after duplicate, must refresh the left list */ - } else if (rightmod.length() > 0) { - modname = rightmod; - refresh = RIGHTPANEL; /* after duplicate, must refresh the right list */ - } - - if (filename.length() == 0) { - wxASSERT(SyncMode); - wxMessageBox(wxT("This part does not exist.")); - return; - } - wxASSERT(filename.length() > 0); - - /* check whether the same library is selected at both sides */ - wxString otherlib = wxEmptyString; - if (refresh < 0) { - long idx = m_choiceModuleRight->GetCurrentSelection(); - if (idx >= 0 && idx < (long)m_choiceModuleRight->GetCount()) - otherlib = m_choiceModuleRight->GetString(idx); - } else if (refresh > 0) { - long idx = m_choiceModuleLeft->GetCurrentSelection(); - if (idx >= 0 && idx < (long)m_choiceModuleLeft->GetCount()) - otherlib = m_choiceModuleLeft->GetString(idx); - } - bool refreshboth = (filename.Cmp(otherlib) == 0); - - CheckSavePart(); - wxTextEntryDialog dlg(this, wxT("New name"), wxT("Duplicate ") + modname, modname); - if (dlg.ShowModal() == wxID_OK) { - wxString newname = dlg.GetValue(); - if (!SymbolMode) { - /* verify that the new name is a valid symbol (in s-expression libraries, - the footprint name is a filename) */ - if (!ValidateFilename(&newname)) - return; - } - if (newname.length() > 0) { - bool result = false; - if (SymbolMode) { - /* first remove the symbol from the library (if it exists) */ - if (ExistSymbol(filename, newname)) { - if (ConfirmOverwrite - && wxMessageBox(wxT("Overwrite \"") + newname + wxT("\"\nin ") + filename + wxT("?"), wxT("Confirm overwrite"), wxYES_NO | wxICON_QUESTION) != wxYES) - return; - RemoveSymbol(filename, newname); - } - wxASSERT(PartData[0].Count() > 0); - wxArrayString symbol = PartData[0]; /* create a copy */ - RenameSymbol(&symbol, modname, newname); - result = InsertSymbol(filename, newname, symbol); - } else { - int type = LibraryType(filename); - if (type == VER_INVALID) { - wxMessageBox(wxT("Unsupported file format for the library.")); - return; - } - /* first remove the footprint from the library (if it exists) */ - if (ConfirmOverwrite - && ExistFootprint(filename, newname) - && wxMessageBox(wxT("Overwrite \"") + newname + wxT("\"\nin ") + filename + wxT("?"), wxT("Confirm overwrite"), wxYES_NO | wxICON_QUESTION) != wxYES) - return; - wxArrayString module; - if (type == VER_S_EXPR) { - /* create full names for source and target, then copy the file */ - wxFileName old_fname(filename, modname + wxT(".kicad_mod")); - wxFileName new_fname(filename, newname + wxT(".kicad_mod")); - result = wxCopyFile(old_fname.GetFullPath(), new_fname.GetFullPath(), true); - /* adjust fields in the new file to newname */ - wxTextFile file; - if (!file.Open(new_fname.GetFullPath())) - return; - /* find the index */ - for (unsigned idx = 0; idx < file.GetLineCount(); idx++) { - wxString line = file.GetLine(idx); - module.Add(line); - } - RenameFootprint(&module, modname, newname); - file.Clear(); - for (unsigned idx = 0; idx < module.Count(); idx++) - file.AddLine(module[idx]); - file.Write(); - file.Close(); - } else { - RemoveFootprint(filename, newname); /* remove the footprint from the target library */ - wxASSERT(PartData[0].Count() > 0); - module = PartData[0]; /* create a copy */ - RenameFootprint(&module, modname, newname); - result = InsertFootprint(filename, newname, module, type >= VER_MM); - } - /* make a copy of the VRML file too */ - if (CopyVRML) - CopyVRMLfile(modname, newname, author, module); - } - if (result) { - wxBusyCursor cursor; - if (refresh < 0 || refreshboth) - HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, LEFTPANEL); - if (refresh > 0 || refreshboth) - HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, RIGHTPANEL); - /* get the index of the new part in the footprint/symbol list */ - wxASSERT(refresh == LEFTPANEL || refresh == RIGHTPANEL); - wxListCtrl* list = (refresh == LEFTPANEL) ? m_listModulesLeft : m_listModulesRight; - long idx; - for (idx = 0; idx < list->GetItemCount(); idx++) { - wxString symbol = list->GetItemText(idx); - if (symbol.Cmp(newname) == 0) - break; - } - wxASSERT(idx < list->GetItemCount()); /* it was just inserted, so it must be found */ - list->SetItemState(idx, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED); - list->EnsureVisible(idx); - LoadPart(idx, list, 0, 0); - UpdateDetails(0); - SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); - SyncScroll(refresh); - m_statusBar->SetStatusText(wxT("Duplicated symbol/footprint")); - m_panelView->Refresh(); - } else { - wxMessageBox(wxT("Operation failed")); - } - } - } + wxString modname, filename, author; + wxString leftmod = GetSelection(m_listModulesLeft, m_choiceModuleLeft, &filename, &author); + wxString rightmod = GetSelection(m_listModulesRight, m_choiceModuleRight, &filename, &author); + wxASSERT(leftmod.IsEmpty() || rightmod.IsEmpty()); + + int refresh = 0; + if (leftmod.length() > 0) { + modname = leftmod; + refresh = LEFTPANEL; /* after duplicate, must refresh the left list */ + } else if (rightmod.length() > 0) { + modname = rightmod; + refresh = RIGHTPANEL; /* after duplicate, must refresh the right list */ + } + + if (filename.length() == 0) { + wxASSERT(SyncMode); + wxMessageBox(wxT("This part does not exist.")); + return; + } + wxASSERT(filename.length() > 0); + + /* check whether the same library is selected at both sides */ + wxString otherlib = wxEmptyString; + if (refresh < 0) { + long idx = m_choiceModuleRight->GetCurrentSelection(); + if (idx >= 0 && idx < (long)m_choiceModuleRight->GetCount()) + otherlib = m_choiceModuleRight->GetString(idx); + } else if (refresh > 0) { + long idx = m_choiceModuleLeft->GetCurrentSelection(); + if (idx >= 0 && idx < (long)m_choiceModuleLeft->GetCount()) + otherlib = m_choiceModuleLeft->GetString(idx); + } + bool refreshboth = (filename.Cmp(otherlib) == 0); + + CheckSavePart(); + wxTextEntryDialog dlg(this, wxT("New name"), wxT("Duplicate ") + modname, modname); + if (dlg.ShowModal() == wxID_OK) { + wxString newname = dlg.GetValue(); + if (!SymbolMode) { + /* verify that the new name is a valid symbol (in s-expression libraries, + the footprint name is a filename) */ + if (!ValidateFilename(&newname)) + return; + } + if (newname.length() > 0) { + bool result = false; + if (SymbolMode) { + /* first remove the symbol from the library (if it exists) */ + if (ExistSymbol(filename, newname)) { + if (ConfirmOverwrite + && wxMessageBox(wxT("Overwrite \"") + newname + wxT("\"\nin ") + filename + wxT("?"), wxT("Confirm overwrite"), wxYES_NO | wxICON_QUESTION) != wxYES) + return; + RemoveSymbol(filename, newname); + } + wxASSERT(PartData[0].Count() > 0); + wxArrayString symbol = PartData[0]; /* create a copy */ + RenameSymbol(&symbol, modname, newname); + result = InsertSymbol(filename, newname, symbol); + } else { + int type = LibraryType(filename); + if (type == VER_INVALID) { + wxMessageBox(wxT("Unsupported file format for the library.")); + return; + } + /* first remove the footprint from the library (if it exists) */ + if (ConfirmOverwrite + && ExistFootprint(filename, newname) + && wxMessageBox(wxT("Overwrite \"") + newname + wxT("\"\nin ") + filename + wxT("?"), wxT("Confirm overwrite"), wxYES_NO | wxICON_QUESTION) != wxYES) + return; + wxArrayString module; + if (type == VER_S_EXPR) { + /* create full names for source and target, then copy the file */ + wxFileName old_fname(filename, modname + wxT(".kicad_mod")); + wxFileName new_fname(filename, newname + wxT(".kicad_mod")); + result = wxCopyFile(old_fname.GetFullPath(), new_fname.GetFullPath(), true); + /* adjust fields in the new file to newname */ + wxTextFile file; + if (!file.Open(new_fname.GetFullPath())) + return; + /* find the index */ + for (unsigned idx = 0; idx < file.GetLineCount(); idx++) { + wxString line = file.GetLine(idx); + module.Add(line); + } + RenameFootprint(&module, modname, newname); + file.Clear(); + for (unsigned idx = 0; idx < module.Count(); idx++) + file.AddLine(module[idx]); + file.Write(); + file.Close(); + } else { + RemoveFootprint(filename, newname); /* remove the footprint from the target library */ + wxASSERT(PartData[0].Count() > 0); + module = PartData[0]; /* create a copy */ + RenameFootprint(&module, modname, newname); + result = InsertFootprint(filename, newname, module, type >= VER_MM); + } + /* make a copy of the VRML file too */ + if (CopyVRML) + CopyVRMLfile(modname, newname, author, module); + } + if (result) { + wxBusyCursor cursor; + if (refresh < 0 || refreshboth) + HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, LEFTPANEL); + if (refresh > 0 || refreshboth) + HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, RIGHTPANEL); + /* get the index of the new part in the footprint/symbol list */ + wxASSERT(refresh == LEFTPANEL || refresh == RIGHTPANEL); + wxListCtrl* list = (refresh == LEFTPANEL) ? m_listModulesLeft : m_listModulesRight; + long idx; + for (idx = 0; idx < list->GetItemCount(); idx++) { + wxString symbol = list->GetItemText(idx); + if (symbol.Cmp(newname) == 0) + break; + } + wxASSERT(idx < list->GetItemCount()); /* it was just inserted, so it must be found */ + list->SetItemState(idx, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED); + list->EnsureVisible(idx); + LoadPart(idx, list, 0, 0); + UpdateDetails(0); + SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); + SyncScroll(refresh); + m_statusBar->SetStatusText(wxT("Duplicated symbol/footprint")); + m_panelView->Refresh(); + } else { + wxMessageBox(wxT("Operation failed")); + } + } + } } bool libmngrFrame::ValidateFilename(wxString* name) { - /* verify that the new name is a valid symbol (in s-expression libraries, - the footprint name is a filename) */ - bool ok; - do { - ok = true; - for (unsigned i = 0; ok && i < wxFileName::GetForbiddenChars().length(); i++) { - if (name->Find(wxFileName::GetForbiddenChars().GetChar(i)) >= 0) { - ok = false; - wxString msg = wxString::Format(wxT("The character '%c' is invalid in a symbol name; please choose a different name"), - wxFileName::GetForbiddenChars().GetChar(i)); - wxTextEntryDialog dlg(this, msg, wxT("Rename ") + *name, *name); - if (dlg.ShowModal() != wxID_OK) - return false; - } - } - } while (!ok); - return true; + /* verify that the new name is a valid symbol (in s-expression libraries, + the footprint name is a filename) */ + bool ok; + do { + ok = true; + for (unsigned i = 0; ok && i < wxFileName::GetForbiddenChars().length(); i++) { + if (name->Find(wxFileName::GetForbiddenChars().GetChar(i)) >= 0) { + ok = false; + wxString msg = wxString::Format(wxT("The character '%c' is invalid in a symbol name; please choose a different name"), + wxFileName::GetForbiddenChars().GetChar(i)); + wxTextEntryDialog dlg(this, msg, wxT("Rename ") + *name, *name); + if (dlg.ShowModal() != wxID_OK) + return false; + } + } + } while (!ok); + return true; } void libmngrFrame::OnLeftLibSelect(wxCommandEvent& /*event*/) { - wxString leftmod = GetSelection(m_listModulesLeft); - if (leftmod.length() > 0) { - PartData[0].Clear(); + wxString leftmod = GetSelection(m_listModulesLeft); + if (leftmod.length() > 0) { + PartData[0].Clear(); #if !defined NO_3DMODEL sceneGraph.clear(); #endif - UpdateDetails(0); - m_panelView->Refresh(); - } - WarnNoRepository(m_choiceModuleLeft); - HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, LEFTPANEL); - SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); - #if !defined NO_CURL - curlCleanup(true); - #endif + UpdateDetails(0); + m_panelView->Refresh(); + } + WarnNoRepository(m_choiceModuleLeft); + HandleLibrarySelect(m_choiceModuleLeft, m_listModulesLeft, LEFTPANEL); + SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); + #if !defined NO_CURL + curlCleanup(true); + #endif } void libmngrFrame::OnRightLibSelect(wxCommandEvent& /*event*/) { - wxString rightmod = GetSelection(m_listModulesRight); - if (rightmod.length() > 0) { - if (CompareMode) { - PartData[1].Clear(); - UpdateDetails(1); - } else { - PartData[0].Clear(); - UpdateDetails(0); - } + wxString rightmod = GetSelection(m_listModulesRight); + if (rightmod.length() > 0) { + if (CompareMode) { + PartData[1].Clear(); + UpdateDetails(1); + } else { + PartData[0].Clear(); + UpdateDetails(0); + } #if !defined NO_3DMODEL sceneGraph.clear(); #endif - m_panelView->Refresh(); - } - WarnNoRepository(m_choiceModuleRight); - HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, RIGHTPANEL); - SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); - #if !defined NO_CURL - curlCleanup(true); - #endif + m_panelView->Refresh(); + } + WarnNoRepository(m_choiceModuleRight); + HandleLibrarySelect(m_choiceModuleRight, m_listModulesRight, RIGHTPANEL); + SynchronizeLibraries(m_listModulesLeft, m_listModulesRight); + #if !defined NO_CURL + curlCleanup(true); + #endif } void libmngrFrame::SyncScroll(int side) { - wxASSERT(side == LEFTPANEL || side == RIGHTPANEL); - if (SyncMode && m_listModulesLeft->GetItemCount() > 0 && m_listModulesRight->GetItemCount() > 0) { - wxListCtrl* src = (side == LEFTPANEL) ? m_listModulesRight : m_listModulesLeft; - wxListCtrl* tgt = (side == LEFTPANEL) ? m_listModulesLeft : m_listModulesRight; - long total = src->GetItemCount(); - wxASSERT(total == tgt->GetItemCount()); - long top = src->GetTopItem(); - long bottom = top + src->GetCountPerPage(); - if (bottom > total) - bottom = total; - tgt->EnsureVisible(top); - tgt->EnsureVisible(bottom - 1); - } + wxASSERT(side == LEFTPANEL || side == RIGHTPANEL); + if (SyncMode && m_listModulesLeft->GetItemCount() > 0 && m_listModulesRight->GetItemCount() > 0) { + wxListCtrl* src = (side == LEFTPANEL) ? m_listModulesRight : m_listModulesLeft; + wxListCtrl* tgt = (side == LEFTPANEL) ? m_listModulesLeft : m_listModulesRight; + long total = src->GetItemCount(); + wxASSERT(total == tgt->GetItemCount()); + long top = src->GetTopItem(); + long bottom = top + src->GetCountPerPage(); + if (bottom > total) + bottom = total; + tgt->EnsureVisible(top); + tgt->EnsureVisible(bottom - 1); + } } void libmngrFrame::OnLeftModSelect(wxListEvent& event) { - CheckSavePart(); - wxBusyCursor cursor; - SelectedPartLeft = event.GetIndex(); - if (!CompareMode) { - EnableButtons(SelectedPartLeft >= 0 ? LEFTPANEL : 0); - RemoveSelection(m_listModulesRight, &SelectedPartRight); - m_radioViewLeft->SetValue(true); - m_radioViewRight->SetValue(false); - OffsetX = OffsetY = 0; + CheckSavePart(); + wxBusyCursor cursor; + SelectedPartLeft = event.GetIndex(); + if (!CompareMode) { + EnableButtons(SelectedPartLeft >= 0 ? LEFTPANEL : 0); + RemoveSelection(m_listModulesRight, &SelectedPartRight); + m_radioViewLeft->SetValue(true); + m_radioViewRight->SetValue(false); + OffsetX = OffsetY = 0; if (ModelMode) { Scale = SCALE_DEFAULT; ResizeModelViewport(); } - } - SyncScroll(RIGHTPANEL); - LoadPart(SelectedPartLeft, m_listModulesLeft, m_choiceModuleLeft, 0); - UpdateDetails(0); + } + SyncScroll(RIGHTPANEL); + LoadPart(SelectedPartLeft, m_listModulesLeft, m_choiceModuleLeft, 0); + UpdateDetails(0); Update3DModel(PartData[0]); - m_panelView->Refresh(); + m_panelView->Refresh(); } void libmngrFrame::OnRightModSelect(wxListEvent& event) { - CheckSavePart(); - wxBusyCursor cursor; - SelectedPartRight = event.GetIndex(); - if (!CompareMode) { - EnableButtons(SelectedPartRight >= 0 ? RIGHTPANEL : 0); - RemoveSelection(m_listModulesLeft, &SelectedPartLeft); - m_radioViewLeft->SetValue(false); - m_radioViewRight->SetValue(true); - OffsetX = OffsetY = 0; + CheckSavePart(); + wxBusyCursor cursor; + SelectedPartRight = event.GetIndex(); + if (!CompareMode) { + EnableButtons(SelectedPartRight >= 0 ? RIGHTPANEL : 0); + RemoveSelection(m_listModulesLeft, &SelectedPartLeft); + m_radioViewLeft->SetValue(false); + m_radioViewRight->SetValue(true); + OffsetX = OffsetY = 0; if (ModelMode) { Scale = SCALE_DEFAULT; ResizeModelViewport(); } - } - SyncScroll(LEFTPANEL); - LoadPart(SelectedPartRight, m_listModulesRight, m_choiceModuleRight, CompareMode ? 1 : 0); - UpdateDetails(CompareMode ? 1 : 0); + } + SyncScroll(LEFTPANEL); + LoadPart(SelectedPartRight, m_listModulesRight, m_choiceModuleRight, CompareMode ? 1 : 0); + UpdateDetails(CompareMode ? 1 : 0); Update3DModel(PartData[0]); - m_panelView->Refresh(); + m_panelView->Refresh(); } void libmngrFrame::OnDetailsPanelUnsplit(wxSplitterEvent& event) { - m_menubar->Check(IDM_DETAILSPANEL, false); - event.Skip(); + m_menubar->Check(IDM_DETAILSPANEL, false); + event.Skip(); } void libmngrFrame::OnViewStartDrag(wxMouseEvent& event) { - DragOrgX = event.GetX() - OffsetX; - DragOrgY = event.GetY() - OffsetY; + DragOrgX = event.GetX() - OffsetX; + DragOrgY = event.GetY() - OffsetY; } void libmngrFrame::OnViewDrag(wxMouseEvent& event) { - if (event.Dragging()) { - OffsetX = event.GetX() - DragOrgX; - OffsetY = event.GetY() - DragOrgY; - m_panelView->Refresh(); - } + if (event.Dragging()) { + OffsetX = event.GetX() - DragOrgX; + OffsetY = event.GetY() - DragOrgY; + m_panelView->Refresh(); + } } void libmngrFrame::OnViewCentre(wxMouseEvent& /*event*/) { - OffsetX = OffsetY = 0; + OffsetX = OffsetY = 0; if (ModelMode) { Scale = SCALE_DEFAULT; ResizeModelViewport(); } - m_panelView->Refresh(); + m_panelView->Refresh(); } void libmngrFrame::OnExportGeneral(wxCommandEvent& /*event*/) { wxString leftpath, rightpath; - wxString leftmod = GetSelection(m_listModulesLeft, m_choiceModuleLeft, &leftpath); - wxString rightmod = GetSelection(m_listModulesRight, m_choiceModuleRight, &rightpath); - wxASSERT(leftmod.IsEmpty() || rightmod.IsEmpty()); - wxString modname, path; + wxString leftmod = GetSelection(m_listModulesLeft, m_choiceModuleLeft, &leftpath); + wxString rightmod = GetSelection(m_listModulesRight, m_choiceModuleRight, &rightpath); + wxASSERT(leftmod.IsEmpty() || rightmod.IsEmpty()); + wxString modname, path; if (leftmod.length() > 0) { modname = leftmod; path = leftpath; @@ -2074,104 +2074,105 @@ void libmngrFrame::OnExportGeneral(wxCommandEvent& /*event*/) return; /* nothing to export */ wxString libname = path.AfterLast(wxT(DIRSEP_CHAR)); - path = path.BeforeLast(wxT(DIRSEP_CHAR)) + wxT(DIRSEP_STR); /* strip filename from the full path */ + wxString dirname = path.BeforeLast(wxT(DIRSEP_CHAR)) + wxT(DIRSEP_STR); /* strip filename from the full path */ - if (SymbolMode) { - ExportSymbolBitmap(modname); - } else { - ExportFootprintBitmap(modname, false, 0, path + wxT("icons")); - ExportFootprintBitmap(modname, true, 1000, path + wxT("layouts")); - CacheMetadata(libname, modname, true, PartData[0], Footprint[0]); + if (SymbolMode) { + ExportSymbolBitmap(modname); + } else { + ExportFootprintBitmap(modname, false, 0, dirname + wxT("icons")); + ExportFootprintBitmap(modname, true, 1000, dirname + wxT("layouts")); + CacheMetadata(path, modname, true, PartData[0], Footprint[0]); + m_statusBar->SetStatusText(wxT("Exported footprint ") + modname); } } wxString libmngrFrame::ExportSymbolBitmap(const wxString& modname) { - /* save a few settings, these are changed only for the image output */ - bool showlabels = ShowLabels; - bool cmpmode = CompareMode; - double scale = Scale; - double offsx = OffsetX; - double offsy = OffsetY; - ShowLabels = true; - CompareMode = false; - OffsetX = OffsetY = 0; - - /* estimate scale from body size */ - double size = (BodySize[0].BodyLength >= BodySize[0].BodyWidth) ? BodySize[0].BodyLength : BodySize[0].BodyWidth; - size += 0.3 * 25.4; /* assume 0.3 inch pins on all sides */ - Scale = IMG_SCALE_SYM / size; - - /* create the bitmaps and DCs */ - wxBitmap *bmp = new wxBitmap(IMG_WIDTH_SYM, IMG_HEIGHT_SYM, 24); - wxMemoryDC *mc = new wxMemoryDC(*bmp); - wxGraphicsContext *gc = wxGraphicsContext::Create(*mc); - /* fill the image with the background colour (default = white) */ - wxBrush brush(clrSchematicMode); - gc->SetBrush(brush); - gc->DrawRectangle(0, 0, IMG_WIDTH_SYM, IMG_HEIGHT_SYM); - - int transp[2] = { wxALPHA_OPAQUE, wxALPHA_OPAQUE }; - DrawSymbols(gc, IMG_WIDTH_SYM / 2, IMG_HEIGHT_SYM / 2, transp); - delete gc; - delete mc; - - /* create the output file */ - wxString path = modname; - int idx; - while ((idx = path.Find('/')) >= 0 || (idx = path.Find('\\')) >= 0) - path[idx] = '-'; - while ((idx = path.Find(' ')) >= 0) - path[idx] = '_'; - path = wxStandardPaths::Get().GetTempDir() + wxT(DIRSEP_STR) + path + wxT(".png"); - bmp->SaveFile(path, wxBITMAP_TYPE_PNG); - delete bmp; - - /* clean up */ - ShowLabels = showlabels; - CompareMode = cmpmode; - Scale = scale; - OffsetX = offsx; - OffsetY = offsy; - - return path; + /* save a few settings, these are changed only for the image output */ + bool showlabels = ShowLabels; + bool cmpmode = CompareMode; + double scale = Scale; + double offsx = OffsetX; + double offsy = OffsetY; + ShowLabels = true; + CompareMode = false; + OffsetX = OffsetY = 0; + + /* estimate scale from body size */ + double size = (BodySize[0].BodyLength >= BodySize[0].BodyWidth) ? BodySize[0].BodyLength : BodySize[0].BodyWidth; + size += 0.3 * 25.4; /* assume 0.3 inch pins on all sides */ + Scale = IMG_SCALE_SYM / size; + + /* create the bitmaps and DCs */ + wxBitmap *bmp = new wxBitmap(IMG_WIDTH_SYM, IMG_HEIGHT_SYM, 24); + wxMemoryDC *mc = new wxMemoryDC(*bmp); + wxGraphicsContext *gc = wxGraphicsContext::Create(*mc); + /* fill the image with the background colour (default = white) */ + wxBrush brush(clrSchematicMode); + gc->SetBrush(brush); + gc->DrawRectangle(0, 0, IMG_WIDTH_SYM, IMG_HEIGHT_SYM); + + int transp[2] = { wxALPHA_OPAQUE, wxALPHA_OPAQUE }; + DrawSymbols(gc, IMG_WIDTH_SYM / 2, IMG_HEIGHT_SYM / 2, transp); + delete gc; + delete mc; + + /* create the output file */ + wxString path = modname; + int idx; + while ((idx = path.Find('/')) >= 0 || (idx = path.Find('\\')) >= 0) + path[idx] = '-'; + while ((idx = path.Find(' ')) >= 0) + path[idx] = '_'; + path = wxStandardPaths::Get().GetTempDir() + wxT(DIRSEP_STR) + path + wxT(".png"); + bmp->SaveFile(path, wxBITMAP_TYPE_PNG); + delete bmp; + + /* clean up */ + ShowLabels = showlabels; + CompareMode = cmpmode; + Scale = scale; + OffsetX = offsx; + OffsetY = offsy; + + return path; } wxString libmngrFrame::ExportFootprintBitmap(const wxString& modname, bool bluescreen, int dpi, const wxString& DestPath) { - /* save a few settings, these are changed only for the image output */ - bool showlabels = ShowLabels; - bool centrecross = DrawCentreCross; - bool pinnumbers = ShowPinNumbers; - bool measurements = ShowMeasurements; - bool cmpmode = CompareMode; + /* save a few settings, these are changed only for the image output */ + bool showlabels = ShowLabels; + bool centrecross = DrawCentreCross; + bool pinnumbers = ShowPinNumbers; + bool measurements = ShowMeasurements; + bool cmpmode = CompareMode; bool outline = OutlineMode; - double scale = Scale; /* save, to be restored later */ - double offsx = OffsetX; - double offsy = OffsetY; - ShowLabels = DrawCentreCross = ShowPinNumbers = ShowMeasurements = CompareMode = false; + double scale = Scale; /* save, to be restored later */ + double offsx = OffsetX; + double offsy = OffsetY; + ShowLabels = DrawCentreCross = ShowPinNumbers = ShowMeasurements = CompareMode = false; OutlineMode = bluescreen; - OffsetX = OffsetY = 0; + OffsetX = OffsetY = 0; int ImgWidth = IMG_WIDTH_FP; int ImgHeight = IMG_HEIGHT_FP; - double padsize = Footprint[0].PadSize[0].GetX() <= Footprint[0].PadSize[0].GetY() ? Footprint[0].PadSize[0].GetX() : Footprint[0].PadSize[0].GetY(); + double padsize = Footprint[0].PadSize[0].GetX() <= Footprint[0].PadSize[0].GetY() ? Footprint[0].PadSize[0].GetX() : Footprint[0].PadSize[0].GetY(); double hsize = BodySize[0].BodyWidth; - double vsize = BodySize[0].BodyLength; - if (hsize < Footprint[0].Pitch + padsize) - hsize = Footprint[0].Pitch + padsize; - if (hsize < Footprint[0].SpanHor + padsize) - hsize = Footprint[0].SpanHor + padsize; - if (vsize < Footprint[0].Pitch + padsize) - vsize = Footprint[0].Pitch + padsize; - if (vsize < Footprint[0].SpanVer + padsize) - vsize = Footprint[0].SpanVer + padsize; + double vsize = BodySize[0].BodyLength; + if (hsize < Footprint[0].Pitch + padsize) + hsize = Footprint[0].Pitch + padsize; + if (hsize < Footprint[0].SpanHor + padsize) + hsize = Footprint[0].SpanHor + padsize; + if (vsize < Footprint[0].Pitch + padsize) + vsize = Footprint[0].Pitch + padsize; + if (vsize < Footprint[0].SpanVer + padsize) + vsize = Footprint[0].SpanVer + padsize; if (dpi == 0) { - /* estimate scale from body size */ + /* estimate scale from body size */ if (hsize > vsize) - Scale = IMG_SCALE_FP / hsize; + Scale = IMG_SCALE_FP / hsize; else - Scale = IMG_SCALE_FP / vsize; + Scale = IMG_SCALE_FP / vsize; if (Scale > 600 / 25.4) Scale = 600 / 25.4; /* limit scale */ } else { @@ -2180,28 +2181,28 @@ wxString libmngrFrame::ExportFootprintBitmap(const wxString& modname, bool blues ImgHeight = (int)(vsize * Scale * 1.25); } - /* create the bitmaps and DCs */ - wxBitmap *bmp = new wxBitmap(ImgWidth, ImgHeight, 24); - wxMemoryDC *mc = new wxMemoryDC(*bmp); + /* create the bitmaps and DCs */ + wxBitmap *bmp = new wxBitmap(ImgWidth, ImgHeight, 24); + wxMemoryDC *mc = new wxMemoryDC(*bmp); if (bluescreen) mc->SetBackground(wxBrush(wxColour(0,0,255))); else mc->SetBackground(*wxBLACK_BRUSH); mc->Clear(); - wxGraphicsContext *gc = wxGraphicsContext::Create(*mc); - - int transp[2] = { wxALPHA_OPAQUE, wxALPHA_OPAQUE }; - DrawFootprints(gc, ImgWidth / 2, ImgHeight / 2, transp); - delete gc; - delete mc; - - /* create the output file */ - wxString path = modname; - int idx; - while ((idx = path.Find('/')) >= 0 || (idx = path.Find('\\')) >= 0) - path[idx] = '-'; - while ((idx = path.Find(' ')) >= 0) - path[idx] = '_'; + wxGraphicsContext *gc = wxGraphicsContext::Create(*mc); + + int transp[2] = { wxALPHA_OPAQUE, wxALPHA_OPAQUE }; + DrawFootprints(gc, ImgWidth / 2, ImgHeight / 2, transp); + delete gc; + delete mc; + + /* create the output file */ + wxString path = modname; + int idx; + while ((idx = path.Find('/')) >= 0 || (idx = path.Find('\\')) >= 0) + path[idx] = '-'; + while ((idx = path.Find(' ')) >= 0) + path[idx] = '_'; path += wxT(".png"); wxString fullpath = DestPath.IsEmpty() ? wxStandardPaths::Get().GetTempDir() : DestPath; int len = fullpath.Length(); @@ -2234,20 +2235,20 @@ wxString libmngrFrame::ExportFootprintBitmap(const wxString& modname, bool blues } else { bmp->SaveFile(fullpath, wxBITMAP_TYPE_PNG); } - delete bmp; - - /* clean up */ - ShowLabels = showlabels; - DrawCentreCross = centrecross; - ShowPinNumbers = pinnumbers; - CompareMode = cmpmode; - Scale = scale; - OffsetX = offsx; - OffsetY = offsy; - ShowMeasurements = measurements; + delete bmp; + + /* clean up */ + ShowLabels = showlabels; + DrawCentreCross = centrecross; + ShowPinNumbers = pinnumbers; + CompareMode = cmpmode; + Scale = scale; + OffsetX = offsx; + OffsetY = offsy; + ShowMeasurements = measurements; OutlineMode = outline; - return fullpath; + return fullpath; } /** Draws a string using the plotter font, using the current pen. The brush is @@ -2255,917 +2256,917 @@ wxString libmngrFrame::ExportFootprintBitmap(const wxString& modname, bool blues */ void libmngrFrame::DrawStrokeText(wxGraphicsContext *gc, float x, float y, const wxString& text) { - /* create a stroke array for the text (applying scale and rotation) */ - std::vector strokes; - VFont.DrawText(text.wc_str(wxConvLibc), &strokes); - - gc->SetBrush(*wxTRANSPARENT_BRUSH); - for (size_t sidx = 0; sidx < strokes.size(); sidx++) { - const CXFPolyLine *stroke = &strokes[sidx]; - wxPoint2DDouble *points = new wxPoint2DDouble[stroke->GetCount()]; - const CXFPoint* pt; - for (size_t pidx = 0; (pt = stroke->GetPoint(pidx)) != 0; pidx++) { - points[pidx].m_x = x + pt->m_x; - points[pidx].m_y = y - pt->m_y; - } - gc->DrawLines(stroke->GetCount(), points); - delete[] points; - } + /* create a stroke array for the text (applying scale and rotation) */ + std::vector strokes; + VFont.DrawText(text.wc_str(wxConvLibc), &strokes); + + gc->SetBrush(*wxTRANSPARENT_BRUSH); + for (size_t sidx = 0; sidx < strokes.size(); sidx++) { + const CXFPolyLine *stroke = &strokes[sidx]; + wxPoint2DDouble *points = new wxPoint2DDouble[stroke->GetCount()]; + const CXFPoint* pt; + for (size_t pidx = 0; (pt = stroke->GetPoint(pidx)) != 0; pidx++) { + points[pidx].m_x = x + pt->m_x; + points[pidx].m_y = y - pt->m_y; + } + gc->DrawLines(stroke->GetCount(), points); + delete[] points; + } } void libmngrFrame::UpdateBoundingBox(CoordSize* bbox, double x, double y) { - wxASSERT(bbox); - if (x < bbox->GetLeft()) - bbox->SetLeft(x); - else if (x > bbox->GetRight()) - bbox->SetRight(x); - if (y < bbox->GetTop()) - bbox->SetTop(y); - else if (y > bbox->GetBottom()) - bbox->SetBottom(y); + wxASSERT(bbox); + if (x < bbox->GetLeft()) + bbox->SetLeft(x); + else if (x > bbox->GetRight()) + bbox->SetRight(x); + if (y < bbox->GetTop()) + bbox->SetTop(y); + else if (y > bbox->GetBottom()) + bbox->SetBottom(y); } void libmngrFrame::DrawSymbols(wxGraphicsContext *gc, int midx, int midy, const int transp[]) { - #define DEFAULTPEN 1 - #define PINSHAPE_SZ 40 - wxBrush brush; - wxColour clrForeground, clrBackground, clrText, clrHiddenText; - double scale = Scale * 0.0254 * 0.25; - double size_pinshape = PINSHAPE_SZ * scale; - - for (int fp = 0; fp < 2; fp++) { - /* check whether the symbol is visible */ - if (fp == 0 && CompareMode && !m_toolBar->GetToolToggled(IDT_LEFTFOOTPRINT)) - continue; - if (fp == 1 && (!CompareMode || !m_toolBar->GetToolToggled(IDT_RIGHTFOOTPRINT))) - continue; - if (PartData[fp].Count() == 0) - continue; - /* Draw the outline, plus optionally the texts */ - if (fp == 0) { - clrForeground.Set(128, 16, 16, transp[fp]); - clrBackground.Set(160, 160, 40, transp[fp]); - clrText.Set(128, 96, 32, transp[fp]); - clrHiddenText.Set(192, 160, 128, transp[fp]); - } else { - clrForeground.Set(16, 128, 16, transp[fp]); - clrBackground.Set(40, 160, 128, transp[fp]); - clrText.Set(128, 32, 128, transp[fp]); - clrHiddenText.Set(192, 128, 192, transp[fp]); - } + #define DEFAULTPEN 1 + #define PINSHAPE_SZ 40 + wxBrush brush; + wxColour clrForeground, clrBackground, clrText, clrHiddenText; + double scale = Scale * 0.0254 * 0.25; + double size_pinshape = PINSHAPE_SZ * scale; + + for (int fp = 0; fp < 2; fp++) { + /* check whether the symbol is visible */ + if (fp == 0 && CompareMode && !m_toolBar->GetToolToggled(IDT_LEFTFOOTPRINT)) + continue; + if (fp == 1 && (!CompareMode || !m_toolBar->GetToolToggled(IDT_RIGHTFOOTPRINT))) + continue; + if (PartData[fp].Count() == 0) + continue; + /* Draw the outline, plus optionally the texts */ + if (fp == 0) { + clrForeground.Set(128, 16, 16, transp[fp]); + clrBackground.Set(160, 160, 40, transp[fp]); + clrText.Set(128, 96, 32, transp[fp]); + clrHiddenText.Set(192, 160, 128, transp[fp]); + } else { + clrForeground.Set(16, 128, 16, transp[fp]); + clrBackground.Set(40, 160, 128, transp[fp]); + clrText.Set(128, 32, 128, transp[fp]); + clrHiddenText.Set(192, 128, 192, transp[fp]); + } for (int pass = 0; pass < 2; pass++) { /* on first pass, only draw filled shapes, on second pass, draw the rest */ - bool indraw = false; - double pinname_offset = size_pinshape; - bool show_pinnr = true, show_pinname = true; - for (int idx = 0; idx < (int)PartData[fp].Count(); idx++) { - wxString line = PartData[fp][idx]; + bool indraw = false; + double pinname_offset = size_pinshape; + bool show_pinnr = true, show_pinname = true; + for (int idx = 0; idx < (int)PartData[fp].Count(); idx++) { + wxString line = PartData[fp][idx]; wxASSERT(line.Length() > 0); - if (line[0] == wxT('#')) - continue; - wxString token = GetToken(&line); - if (token.CmpNoCase(wxT("DEF")) == 0 && pass > 0) { - GetToken(&line); /* ignore name */ - GetToken(&line); /* ignore designator prefix */ - GetToken(&line); /* ignore reserved field */ - pinname_offset = GetTokenLong(&line) * scale; - show_pinnr = GetToken(&line) == wxT('Y'); - show_pinname = GetToken(&line) == wxT('Y'); - } else if (token[0] == wxT('F') && token.Length() >= 2 && isdigit(token[1]) && pass > 0) { - if (ShowLabels) { - wxString name = GetToken(&line); - double x = midx + GetTokenLong(&line) * scale; - double y = midy - GetTokenLong(&line) * scale; - long rawsize = GetTokenLong(&line); - double size = rawsize * scale; - wxString orient = GetToken(&line); - int angle = (orient == wxT('V')) ? 90 : 0; - wxString visflag = GetToken(&line); - bool visible = (visflag == wxT('V')); - wxString align = GetToken(&line); - int horalign = CXF_ALIGNCENTRE; - switch ((int)align[0]) { - case 'L': - horalign = CXF_ALIGNLEFT; - break; - case 'R': - horalign = CXF_ALIGNRIGHT; - break; - } - align = GetToken(&line); - int veralign = CXF_ALIGNCENTRE; - switch ((int)align[0]) { - case 'T': - veralign = CXF_ALIGNTOP; - break; - case 'B': - veralign = CXF_ALIGNBOTTOM; - break; - } - bool bold = (align.Length() >= 3 && align[2] == wxT('B')); - double penwidth = bold ? (size * 0.25) : (size * 0.15); - if (penwidth < DEFAULTPEN) - penwidth = DEFAULTPEN; - if (rawsize > 5) { - wxColour penclr = visible ? clrText : clrHiddenText; - wxPen pen(penclr, penwidth); - gc->SetPen(pen); - if (name.Length() > 0 && name[0] == '~') - name = name.Mid(1); - VFont.SetScale(size / CXF_CAPSHEIGHT, size / CXF_CAPSHEIGHT); + if (line[0] == wxT('#')) + continue; + wxString token = GetToken(&line); + if (token.CmpNoCase(wxT("DEF")) == 0 && pass > 0) { + GetToken(&line); /* ignore name */ + GetToken(&line); /* ignore designator prefix */ + GetToken(&line); /* ignore reserved field */ + pinname_offset = GetTokenLong(&line) * scale; + show_pinnr = GetToken(&line) == wxT('Y'); + show_pinname = GetToken(&line) == wxT('Y'); + } else if (token[0] == wxT('F') && token.Length() >= 2 && isdigit(token[1]) && pass > 0) { + if (ShowLabels) { + wxString name = GetToken(&line); + double x = midx + GetTokenLong(&line) * scale; + double y = midy - GetTokenLong(&line) * scale; + long rawsize = GetTokenLong(&line); + double size = rawsize * scale; + wxString orient = GetToken(&line); + int angle = (orient == wxT('V')) ? 90 : 0; + wxString visflag = GetToken(&line); + bool visible = (visflag == wxT('V')); + wxString align = GetToken(&line); + int horalign = CXF_ALIGNCENTRE; + switch ((int)align[0]) { + case 'L': + horalign = CXF_ALIGNLEFT; + break; + case 'R': + horalign = CXF_ALIGNRIGHT; + break; + } + align = GetToken(&line); + int veralign = CXF_ALIGNCENTRE; + switch ((int)align[0]) { + case 'T': + veralign = CXF_ALIGNTOP; + break; + case 'B': + veralign = CXF_ALIGNBOTTOM; + break; + } + bool bold = (align.Length() >= 3 && align[2] == wxT('B')); + double penwidth = bold ? (size * 0.25) : (size * 0.15); + if (penwidth < DEFAULTPEN) + penwidth = DEFAULTPEN; + if (rawsize > 5) { + wxColour penclr = visible ? clrText : clrHiddenText; + wxPen pen(penclr, penwidth); + gc->SetPen(pen); + if (name.Length() > 0 && name[0] == '~') + name = name.Mid(1); + VFont.SetScale(size / CXF_CAPSHEIGHT, size / CXF_CAPSHEIGHT); VFont.SetItalic(false); - VFont.SetOverbar(false); - VFont.SetRotation(angle); - VFont.SetAlign(horalign, veralign); - DrawStrokeText(gc, x, y, name); - } - } - } else if (token.CmpNoCase(wxT("DRAW")) == 0) { - indraw = true; - } else if (token.CmpNoCase(wxT("ENDDRAW")) == 0) { - indraw = false; - } else if (indraw) { - double x, y, w, h, penwidth, length, size_nr, size_name, angle, endangle; - long count, orientation, bold, halign, valign; - bool visible, italic; - wxPoint2DDouble *points; - wxGraphicsPath path; - wxString name, pin, field; - wxPen pen(clrForeground); - switch ((int)token[0]) { - case 'A': - x = midx + GetTokenLong(&line) * scale; - y = midy - GetTokenLong(&line) * scale; - w = GetTokenLong(&line) * scale; - angle = GetTokenLong(&line) * M_PI / 1800.0; - endangle = GetTokenLong(&line) * M_PI / 1800.0; - if (GetTokenLong(&line) > 1) - break; /* ignore parts other than part 1 */ - if (GetTokenLong(&line) > 1) - break; /* ignore De Morgan converted shape */ - if ((penwidth = GetTokenLong(&line) * scale) < DEFAULTPEN) - penwidth = DEFAULTPEN; - field = GetToken(&line); /* fill parameter (save, analyze later) */ - if (((field == wxT('f') || field == wxT('F')) && pass == 0) || (field == wxT('N') && pass > 0)) { - pen.SetWidth(penwidth); - gc->SetPen(pen); - if (field == wxT('f')) - gc->SetBrush(clrBackground); - else if (field == wxT('F')) - gc->SetBrush(clrForeground); - else - gc->SetBrush(*wxTRANSPARENT_BRUSH); - path = gc->CreatePath(); - /* calculate the angle of rotation */ - while (angle > M_PI) - angle -= 2*M_PI; - while (angle < -M_PI) - angle += 2*M_PI; - while (endangle > M_PI) - endangle -= 2*M_PI; - while (endangle < angle) - endangle += 2*M_PI; - h = endangle - angle; - wxASSERT(h > -EPSILON); - wxASSERT(h < 2*M_PI + EPSILON); - path.AddArc(x, y, w, -angle, -endangle, (h > M_PI)); - gc->DrawPath(path); + VFont.SetOverbar(false); + VFont.SetRotation(angle); + VFont.SetAlign(horalign, veralign); + DrawStrokeText(gc, x, y, name); + } + } + } else if (token.CmpNoCase(wxT("DRAW")) == 0) { + indraw = true; + } else if (token.CmpNoCase(wxT("ENDDRAW")) == 0) { + indraw = false; + } else if (indraw) { + double x, y, w, h, penwidth, length, size_nr, size_name, angle, endangle; + long count, orientation, bold, halign, valign; + bool visible, italic; + wxPoint2DDouble *points; + wxGraphicsPath path; + wxString name, pin, field; + wxPen pen(clrForeground); + switch ((int)token[0]) { + case 'A': + x = midx + GetTokenLong(&line) * scale; + y = midy - GetTokenLong(&line) * scale; + w = GetTokenLong(&line) * scale; + angle = GetTokenLong(&line) * M_PI / 1800.0; + endangle = GetTokenLong(&line) * M_PI / 1800.0; + if (GetTokenLong(&line) > 1) + break; /* ignore parts other than part 1 */ + if (GetTokenLong(&line) > 1) + break; /* ignore De Morgan converted shape */ + if ((penwidth = GetTokenLong(&line) * scale) < DEFAULTPEN) + penwidth = DEFAULTPEN; + field = GetToken(&line); /* fill parameter (save, analyze later) */ + if (((field == wxT('f') || field == wxT('F')) && pass == 0) || (field == wxT('N') && pass > 0)) { + pen.SetWidth(penwidth); + gc->SetPen(pen); + if (field == wxT('f')) + gc->SetBrush(clrBackground); + else if (field == wxT('F')) + gc->SetBrush(clrForeground); + else + gc->SetBrush(*wxTRANSPARENT_BRUSH); + path = gc->CreatePath(); + /* calculate the angle of rotation */ + while (angle > M_PI) + angle -= 2*M_PI; + while (angle < -M_PI) + angle += 2*M_PI; + while (endangle > M_PI) + endangle -= 2*M_PI; + while (endangle < angle) + endangle += 2*M_PI; + h = endangle - angle; + wxASSERT(h > -EPSILON); + wxASSERT(h < 2*M_PI + EPSILON); + path.AddArc(x, y, w, -angle, -endangle, (h > M_PI)); + gc->DrawPath(path); + } + break; + case 'B': + //??? Bezier curves apparently not yet handled by the KiCad Symbol Editor + break; + case 'C': + x = midx + GetTokenLong(&line) * scale; + y = midy - GetTokenLong(&line) * scale; + w = GetTokenLong(&line) * scale; + if (GetTokenLong(&line) > 1) + break; /* ignore parts other than part 1 */ + if (GetTokenLong(&line) > 1) + break; /* ignore De Morgan converted shape */ + if ((penwidth = GetTokenLong(&line) * scale) < DEFAULTPEN) + penwidth = DEFAULTPEN; + field = GetToken(&line); + if (((field == wxT('f') || field == wxT('F')) && pass == 0) || (field == wxT('N') && pass > 0)) { + pen.SetWidth(penwidth); + gc->SetPen(pen); + if (field == wxT('f')) + gc->SetBrush(clrBackground); + else if (field == wxT('F')) + gc->SetBrush(clrForeground); + else + gc->SetBrush(*wxTRANSPARENT_BRUSH); + gc->DrawEllipse(x - w, y - w, 2 * w, 2 * w); } - break; - case 'B': - //??? Bezier curves apparently not yet handled by the KiCad Symbol Editor - break; - case 'C': - x = midx + GetTokenLong(&line) * scale; - y = midy - GetTokenLong(&line) * scale; - w = GetTokenLong(&line) * scale; - if (GetTokenLong(&line) > 1) - break; /* ignore parts other than part 1 */ - if (GetTokenLong(&line) > 1) - break; /* ignore De Morgan converted shape */ - if ((penwidth = GetTokenLong(&line) * scale) < DEFAULTPEN) - penwidth = DEFAULTPEN; - field = GetToken(&line); - if (((field == wxT('f') || field == wxT('F')) && pass == 0) || (field == wxT('N') && pass > 0)) { - pen.SetWidth(penwidth); - gc->SetPen(pen); - if (field == wxT('f')) - gc->SetBrush(clrBackground); - else if (field == wxT('F')) - gc->SetBrush(clrForeground); - else - gc->SetBrush(*wxTRANSPARENT_BRUSH); - gc->DrawEllipse(x - w, y - w, 2 * w, 2 * w); + break; + case 'P': + count = (int)GetTokenLong(&line); + if (GetTokenLong(&line) > 1) + break; /* ignore parts other than part 1 */ + if (GetTokenLong(&line) > 1) + break; /* ignore De Morgan converted shape */ + if ((penwidth = GetTokenLong(&line) * scale) < DEFAULTPEN) + penwidth = DEFAULTPEN; + wxASSERT(count > 0); + points = new wxPoint2DDouble[count + 1]; /* reserve 1 extra for filled polygons */ + wxASSERT(points != NULL); + for (int p = 0; p < count; p++) { + points[p].m_x = midx + GetTokenLong(&line) * scale; + points[p].m_y = midy - GetTokenLong(&line) * scale; } - break; - case 'P': - count = (int)GetTokenLong(&line); - if (GetTokenLong(&line) > 1) - break; /* ignore parts other than part 1 */ - if (GetTokenLong(&line) > 1) - break; /* ignore De Morgan converted shape */ - if ((penwidth = GetTokenLong(&line) * scale) < DEFAULTPEN) - penwidth = DEFAULTPEN; - wxASSERT(count > 0); - points = new wxPoint2DDouble[count + 1]; /* reserve 1 extra for filled polygons */ - wxASSERT(points != NULL); - for (int p = 0; p < count; p++) { - points[p].m_x = midx + GetTokenLong(&line) * scale; - points[p].m_y = midy - GetTokenLong(&line) * scale; - } - field = GetToken(&line); - if (((field == wxT('f') || field == wxT('F')) && pass == 0) || (field == wxT('N') && pass > 0)) { - if (field == wxT('F') || field == wxT('f')) { - /* filled polygons are implicitly closed */ - points[count] = points[0]; - count += 1; - } - pen.SetWidth(penwidth); - gc->SetPen(pen); - if (field == wxT('f')) - gc->SetBrush(clrBackground); - else if (field == wxT('F')) - gc->SetBrush(clrForeground); - else - gc->SetBrush(*wxTRANSPARENT_BRUSH); - gc->DrawLines(count, points); + field = GetToken(&line); + if (((field == wxT('f') || field == wxT('F')) && pass == 0) || (field == wxT('N') && pass > 0)) { + if (field == wxT('F') || field == wxT('f')) { + /* filled polygons are implicitly closed */ + points[count] = points[0]; + count += 1; + } + pen.SetWidth(penwidth); + gc->SetPen(pen); + if (field == wxT('f')) + gc->SetBrush(clrBackground); + else if (field == wxT('F')) + gc->SetBrush(clrForeground); + else + gc->SetBrush(*wxTRANSPARENT_BRUSH); + gc->DrawLines(count, points); } - delete[] points; - break; - case 'S': - x = GetTokenLong(&line) * scale; - y = GetTokenLong(&line) * scale; - w = GetTokenLong(&line) * scale - x; - h = GetTokenLong(&line) * scale - y; - if (GetTokenLong(&line) > 1) - break; /* ignore parts other than part 1 */ - if (GetTokenLong(&line) > 1) - break; /* ignore De Morgan converted shape */ - if ((penwidth = GetTokenLong(&line) * scale) < DEFAULTPEN) - penwidth = DEFAULTPEN; - field = GetToken(&line); - if (((field == wxT('f') || field == wxT('F')) && pass == 0) || (field == wxT('N') && pass > 0)) { - if (w < 0) { - x += w; - w = -w; - } - if (h < 0) { - y += h; - h = -h; - } - pen.SetWidth(penwidth); - gc->SetPen(pen); - if (field == wxT('f')) - gc->SetBrush(clrBackground); - else if (field == wxT('F')) - gc->SetBrush(clrForeground); - else - gc->SetBrush(*wxTRANSPARENT_BRUSH); - gc->DrawRectangle(midx + x, midy - (y + h), w, h); + delete[] points; + break; + case 'S': + x = GetTokenLong(&line) * scale; + y = GetTokenLong(&line) * scale; + w = GetTokenLong(&line) * scale - x; + h = GetTokenLong(&line) * scale - y; + if (GetTokenLong(&line) > 1) + break; /* ignore parts other than part 1 */ + if (GetTokenLong(&line) > 1) + break; /* ignore De Morgan converted shape */ + if ((penwidth = GetTokenLong(&line) * scale) < DEFAULTPEN) + penwidth = DEFAULTPEN; + field = GetToken(&line); + if (((field == wxT('f') || field == wxT('F')) && pass == 0) || (field == wxT('N') && pass > 0)) { + if (w < 0) { + x += w; + w = -w; + } + if (h < 0) { + y += h; + h = -h; + } + pen.SetWidth(penwidth); + gc->SetPen(pen); + if (field == wxT('f')) + gc->SetBrush(clrBackground); + else if (field == wxT('F')) + gc->SetBrush(clrForeground); + else + gc->SetBrush(*wxTRANSPARENT_BRUSH); + gc->DrawRectangle(midx + x, midy - (y + h), w, h); } - break; - case 'T': + break; + case 'T': if (pass > 0) { - angle = GetTokenLong(&line) / 10.0; - x = midx + GetTokenLong(&line) * scale; - y = midy - GetTokenLong(&line) * scale; - h = GetTokenLong(&line) * scale; /* text size */ - visible = GetTokenLong(&line) == 0; - if (GetTokenLong(&line) > 1) - break; /* ignore parts other than part 1 */ - if (GetTokenLong(&line) > 1) - break; /* ignore De Morgan converted shape */ - name = GetToken(&line); - field = GetToken(&line); + angle = GetTokenLong(&line) / 10.0; + x = midx + GetTokenLong(&line) * scale; + y = midy - GetTokenLong(&line) * scale; + h = GetTokenLong(&line) * scale; /* text size */ + visible = GetTokenLong(&line) == 0; + if (GetTokenLong(&line) > 1) + break; /* ignore parts other than part 1 */ + if (GetTokenLong(&line) > 1) + break; /* ignore De Morgan converted shape */ + name = GetToken(&line); + field = GetToken(&line); italic = field.CmpNoCase(wxT("italic")) == 0; - bold = GetTokenLong(&line); - field = GetToken(&line); - if (field == wxT('L')) - halign = CXF_ALIGNLEFT; - else if (field == wxT('R')) - halign = CXF_ALIGNRIGHT; - else - halign = CXF_ALIGNCENTRE; - field = GetToken(&line); - if (field == wxT('T')) - valign = CXF_ALIGNTOP; - else if (field == wxT('B')) - valign = CXF_ALIGNBOTTOM; - else - valign = CXF_ALIGNCENTRE; - pen.SetWidth(bold ? h * 0.25 : h * 0.15); - pen.SetColour(visible ? clrText : clrHiddenText); - gc->SetPen(pen); - VFont.SetScale(h / CXF_CAPSHEIGHT, h / CXF_CAPSHEIGHT); + bold = GetTokenLong(&line); + field = GetToken(&line); + if (field == wxT('L')) + halign = CXF_ALIGNLEFT; + else if (field == wxT('R')) + halign = CXF_ALIGNRIGHT; + else + halign = CXF_ALIGNCENTRE; + field = GetToken(&line); + if (field == wxT('T')) + valign = CXF_ALIGNTOP; + else if (field == wxT('B')) + valign = CXF_ALIGNBOTTOM; + else + valign = CXF_ALIGNCENTRE; + pen.SetWidth(bold ? h * 0.25 : h * 0.15); + pen.SetColour(visible ? clrText : clrHiddenText); + gc->SetPen(pen); + VFont.SetScale(h / CXF_CAPSHEIGHT, h / CXF_CAPSHEIGHT); VFont.SetItalic(italic); - VFont.SetOverbar(false); - VFont.SetRotation((int)angle); - VFont.SetAlign(halign, valign); - DrawStrokeText(gc, x, y, name); + VFont.SetOverbar(false); + VFont.SetRotation((int)angle); + VFont.SetAlign(halign, valign); + DrawStrokeText(gc, x, y, name); } - break; - case 'X': + break; + case 'X': if (pass > 0) { - name = GetToken(&line); - if (name == wxT('~')) - name = wxEmptyString; - pin = GetToken(&line); - if (pin == wxT('~')) - pin = wxEmptyString; - points = new wxPoint2DDouble[2]; - wxASSERT(points != NULL); - points[0].m_x = midx + GetTokenLong(&line) * scale; - points[0].m_y = midy - GetTokenLong(&line) * scale; - length = GetTokenLong(&line) * scale; - field = GetToken(&line); - orientation = field[0]; - size_nr = GetTokenLong(&line) * scale; - size_name = GetTokenLong(&line) * scale; - if (GetTokenLong(&line) > 1) - break; /* ignore parts other than part 1 */ - if (GetTokenLong(&line) > 1) - break; /* ignore De Morgan converted shape */ - GetToken(&line); /* ignore type */ - field = GetToken(&line); /* pin shape */ - points[1] = points[0]; - switch (orientation) { - case 'L': - points[1].m_x = points[0].m_x - length; - angle = 0; - break; - case 'R': - points[1].m_x = points[0].m_x + length; - angle = 0; - break; - case 'U': - points[1].m_y = points[0].m_y - length; - angle = 90; - break; - case 'D': - points[1].m_y = points[0].m_y + length; - angle = 90; - break; - default: - wxASSERT(false); - angle = 0; /* just to avoid a compiler warning */ - } - pen.SetWidth(DEFAULTPEN); - gc->SetPen(pen); - gc->DrawLines(2, points); - if (field.Length() > 0) { - gc->SetBrush(clrBackground); - if (field == wxT('I') || field == wxT("CI")) { - /* inverted or inverted clock */ - wxPoint2DDouble ptShape = points[1]; - if (!Equal(points[0].m_x, ptShape.m_x)) { - int sign = (points[0].m_x < ptShape.m_x) ? -1 : 1; - ptShape.m_x += sign * (size_pinshape + 1) / 2; - } else if (!Equal(points[0].m_y, ptShape.m_y)) { - int sign = (points[0].m_y < ptShape.m_y) ? -1 : 1; - ptShape.m_y += sign * (size_pinshape + 1) / 2; - } - gc->DrawEllipse(ptShape.m_x - size_pinshape / 2, ptShape.m_y - size_pinshape / 2, size_pinshape, size_pinshape); - } - if (field == wxT('C') || field == wxT("CI")) { - /* clock or inverted clock */ - wxPoint2DDouble ptShape[3]; - for (int i = 0; i < 3; i++) - ptShape[i] = points[1]; - if (!Equal(points[0].m_x, ptShape[1].m_x)) { - int sign = (points[0].m_x < ptShape[1].m_x) ? 1 : -1; - ptShape[1].m_x += sign * (size_pinshape + 1) / 2; - ptShape[0].m_y -= (size_pinshape + 1) / 2; - ptShape[2].m_y += (size_pinshape + 1) / 2; - } else if (!Equal(points[0].m_y, ptShape[1].m_y)) { - int sign = (points[0].m_y < ptShape[1].m_y) ? 1 : -1; - ptShape[1].m_y += sign * (size_pinshape + 1) / 2; - ptShape[0].m_x -= (size_pinshape + 1) / 2; - ptShape[2].m_x += (size_pinshape + 1) / 2; - } - gc->DrawLines(3, ptShape); - } - } - gc->SetBrush(clrForeground); - gc->DrawEllipse(points[0].m_x - 2, points[0].m_y - 2, 4, 4); /* cicle at the endpoint */ - /* pin name and number */ - pen.SetColour(clrText); - if (show_pinnr) { - pen.SetWidth(size_nr * 0.125); - gc->SetPen(pen); - VFont.SetScale(size_nr / CXF_CAPSHEIGHT, size_nr / CXF_CAPSHEIGHT); + name = GetToken(&line); + if (name == wxT('~')) + name = wxEmptyString; + pin = GetToken(&line); + if (pin == wxT('~')) + pin = wxEmptyString; + points = new wxPoint2DDouble[2]; + wxASSERT(points != NULL); + points[0].m_x = midx + GetTokenLong(&line) * scale; + points[0].m_y = midy - GetTokenLong(&line) * scale; + length = GetTokenLong(&line) * scale; + field = GetToken(&line); + orientation = field[0]; + size_nr = GetTokenLong(&line) * scale; + size_name = GetTokenLong(&line) * scale; + if (GetTokenLong(&line) > 1) + break; /* ignore parts other than part 1 */ + if (GetTokenLong(&line) > 1) + break; /* ignore De Morgan converted shape */ + GetToken(&line); /* ignore type */ + field = GetToken(&line); /* pin shape */ + points[1] = points[0]; + switch (orientation) { + case 'L': + points[1].m_x = points[0].m_x - length; + angle = 0; + break; + case 'R': + points[1].m_x = points[0].m_x + length; + angle = 0; + break; + case 'U': + points[1].m_y = points[0].m_y - length; + angle = 90; + break; + case 'D': + points[1].m_y = points[0].m_y + length; + angle = 90; + break; + default: + wxASSERT(false); + angle = 0; /* just to avoid a compiler warning */ + } + pen.SetWidth(DEFAULTPEN); + gc->SetPen(pen); + gc->DrawLines(2, points); + if (field.Length() > 0) { + gc->SetBrush(clrBackground); + if (field == wxT('I') || field == wxT("CI")) { + /* inverted or inverted clock */ + wxPoint2DDouble ptShape = points[1]; + if (!Equal(points[0].m_x, ptShape.m_x)) { + int sign = (points[0].m_x < ptShape.m_x) ? -1 : 1; + ptShape.m_x += sign * (size_pinshape + 1) / 2; + } else if (!Equal(points[0].m_y, ptShape.m_y)) { + int sign = (points[0].m_y < ptShape.m_y) ? -1 : 1; + ptShape.m_y += sign * (size_pinshape + 1) / 2; + } + gc->DrawEllipse(ptShape.m_x - size_pinshape / 2, ptShape.m_y - size_pinshape / 2, size_pinshape, size_pinshape); + } + if (field == wxT('C') || field == wxT("CI")) { + /* clock or inverted clock */ + wxPoint2DDouble ptShape[3]; + for (int i = 0; i < 3; i++) + ptShape[i] = points[1]; + if (!Equal(points[0].m_x, ptShape[1].m_x)) { + int sign = (points[0].m_x < ptShape[1].m_x) ? 1 : -1; + ptShape[1].m_x += sign * (size_pinshape + 1) / 2; + ptShape[0].m_y -= (size_pinshape + 1) / 2; + ptShape[2].m_y += (size_pinshape + 1) / 2; + } else if (!Equal(points[0].m_y, ptShape[1].m_y)) { + int sign = (points[0].m_y < ptShape[1].m_y) ? 1 : -1; + ptShape[1].m_y += sign * (size_pinshape + 1) / 2; + ptShape[0].m_x -= (size_pinshape + 1) / 2; + ptShape[2].m_x += (size_pinshape + 1) / 2; + } + gc->DrawLines(3, ptShape); + } + } + gc->SetBrush(clrForeground); + gc->DrawEllipse(points[0].m_x - 2, points[0].m_y - 2, 4, 4); /* cicle at the endpoint */ + /* pin name and number */ + pen.SetColour(clrText); + if (show_pinnr) { + pen.SetWidth(size_nr * 0.125); + gc->SetPen(pen); + VFont.SetScale(size_nr / CXF_CAPSHEIGHT, size_nr / CXF_CAPSHEIGHT); VFont.SetItalic(false); - VFont.SetOverbar(false); - VFont.SetRotation((int)angle); - VFont.SetAlign(CXF_ALIGNCENTRE, CXF_ALIGNBOTTOM); - if (angle > EPSILON) { - x = points[1].m_x; - y = (points[0].m_y + points[1].m_y) / 2; - } else { - x = (points[0].m_x + points[1].m_x) / 2; - y = points[1].m_y; - } - DrawStrokeText(gc, x, y, pin); - } - if (show_pinname) { - pen.SetWidth(size_name * 0.15); - gc->SetPen(pen); - VFont.SetScale(size_name / CXF_CAPSHEIGHT, size_name / CXF_CAPSHEIGHT); + VFont.SetOverbar(false); + VFont.SetRotation((int)angle); + VFont.SetAlign(CXF_ALIGNCENTRE, CXF_ALIGNBOTTOM); + if (angle > EPSILON) { + x = points[1].m_x; + y = (points[0].m_y + points[1].m_y) / 2; + } else { + x = (points[0].m_x + points[1].m_x) / 2; + y = points[1].m_y; + } + DrawStrokeText(gc, x, y, pin); + } + if (show_pinname) { + pen.SetWidth(size_name * 0.15); + gc->SetPen(pen); + VFont.SetScale(size_name / CXF_CAPSHEIGHT, size_name / CXF_CAPSHEIGHT); VFont.SetItalic(false); - if (name.length() > 0 && name[0] == wxT('~')) { - name = name.Mid(1); - VFont.SetOverbar(true); - } - if (pinname_offset < EPSILON) { - /* pin name is outside the shape */ - VFont.SetAlign(CXF_ALIGNCENTRE, CXF_ALIGNTOP); - if (angle > EPSILON) { - x = points[1].m_x; - y = (points[0].m_y + points[1].m_y) / 2; - } else { - x = (points[0].m_x + points[1].m_x) / 2; - y = points[1].m_y; - } - } else { - /* pin name is inside the shape */ - if (pinname_offset < size_name / 2) - pinname_offset = size_name / 2; - if (angle > EPSILON) { - x = points[1].m_x; - if (points[0].m_y < points[1].m_y) { - y = points[1].m_y + pinname_offset; - VFont.SetAlign(CXF_ALIGNRIGHT, CXF_ALIGNCENTRE); - } else { - y = points[1].m_y - pinname_offset; - VFont.SetAlign(CXF_ALIGNLEFT, CXF_ALIGNCENTRE); - } - } else { - if (points[0].m_x < points[1].m_x) { - x = points[1].m_x + pinname_offset; - VFont.SetAlign(CXF_ALIGNLEFT, CXF_ALIGNCENTRE); - } else { - x = points[1].m_x - pinname_offset; - VFont.SetAlign(CXF_ALIGNRIGHT, CXF_ALIGNCENTRE); - } - y = points[1].m_y; - } - } - DrawStrokeText(gc, x, y, name); - } - delete[] points; + if (name.length() > 0 && name[0] == wxT('~')) { + name = name.Mid(1); + VFont.SetOverbar(true); + } + if (pinname_offset < EPSILON) { + /* pin name is outside the shape */ + VFont.SetAlign(CXF_ALIGNCENTRE, CXF_ALIGNTOP); + if (angle > EPSILON) { + x = points[1].m_x; + y = (points[0].m_y + points[1].m_y) / 2; + } else { + x = (points[0].m_x + points[1].m_x) / 2; + y = points[1].m_y; + } + } else { + /* pin name is inside the shape */ + if (pinname_offset < size_name / 2) + pinname_offset = size_name / 2; + if (angle > EPSILON) { + x = points[1].m_x; + if (points[0].m_y < points[1].m_y) { + y = points[1].m_y + pinname_offset; + VFont.SetAlign(CXF_ALIGNRIGHT, CXF_ALIGNCENTRE); + } else { + y = points[1].m_y - pinname_offset; + VFont.SetAlign(CXF_ALIGNLEFT, CXF_ALIGNCENTRE); + } + } else { + if (points[0].m_x < points[1].m_x) { + x = points[1].m_x + pinname_offset; + VFont.SetAlign(CXF_ALIGNLEFT, CXF_ALIGNCENTRE); + } else { + x = points[1].m_x - pinname_offset; + VFont.SetAlign(CXF_ALIGNRIGHT, CXF_ALIGNCENTRE); + } + y = points[1].m_y; + } + } + DrawStrokeText(gc, x, y, name); + } + delete[] points; } - break; - } /* switch token */ - } - } /* for (idx over PartData[fp]) */ + break; + } /* switch token */ + } + } /* for (idx over PartData[fp]) */ } /* for (pass) */ - } + } } void libmngrFrame::DrawFootprints(wxGraphicsContext *gc, int midx, int midy, const int transp[]) { - CoordSize bbox; - wxColour clrBody, clrPad, clrPadFill, clrText, clrHiddenText; - wxPoint2DDouble points[5]; - wxPen pen; - - /* check whether there is at least one footprint visible */ - if (PartData[0].Count() == 0 && PartData[1].Count() == 0) { - clrText.Set(128, 128, 128); - wxFont font(24, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD); - font.SetPointSize(24); - gc->SetFont(font, clrText); - wxString text = wxT("FOOTPRINT DOES NOT EXIST"); - wxDouble tw, th, td, tex; - gc->GetTextExtent(text, &tw, &th, &td, &tex); - gc->DrawText(text, midx - tw/2, midy - th/2); - return; - } - - for (int fp = 0; fp < 2; fp++) { - /* check whether the footprint is visible */ - if (fp == 0 && CompareMode && !m_toolBar->GetToolToggled(IDT_LEFTFOOTPRINT)) - continue; - if (fp == 1 && (!CompareMode || !m_toolBar->GetToolToggled(IDT_RIGHTFOOTPRINT))) - continue; - if (PartData[fp].Count() == 0) - continue; - if (fp == 0) { - clrBody.Set(192, 192, 96, transp[fp]); - clrPad.Set(160, 0, 0, transp[fp]); - clrPadFill.Set(160, 48, 48, transp[fp]); - clrText.Set(240, 240, 64, transp[fp]); - clrHiddenText.Set(160, 160, 50, transp[fp]); - } else { - clrBody.Set(192, 96, 192, transp[fp]); - clrPad.Set(0, 160, 0, transp[fp]); - clrPadFill.Set(48, 160, 48, transp[fp]); - clrText.Set(240, 64, 240, transp[fp]); - clrHiddenText.Set(160, 50, 160, transp[fp]); - } + CoordSize bbox; + wxColour clrBody, clrPad, clrPadFill, clrText, clrHiddenText; + wxPoint2DDouble points[5]; + wxPen pen; + + /* check whether there is at least one footprint visible */ + if (PartData[0].Count() == 0 && PartData[1].Count() == 0) { + clrText.Set(128, 128, 128); + wxFont font(24, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD); + font.SetPointSize(24); + gc->SetFont(font, clrText); + wxString text = wxT("FOOTPRINT DOES NOT EXIST"); + wxDouble tw, th, td, tex; + gc->GetTextExtent(text, &tw, &th, &td, &tex); + gc->DrawText(text, midx - tw/2, midy - th/2); + return; + } + + for (int fp = 0; fp < 2; fp++) { + /* check whether the footprint is visible */ + if (fp == 0 && CompareMode && !m_toolBar->GetToolToggled(IDT_LEFTFOOTPRINT)) + continue; + if (fp == 1 && (!CompareMode || !m_toolBar->GetToolToggled(IDT_RIGHTFOOTPRINT))) + continue; + if (PartData[fp].Count() == 0) + continue; + if (fp == 0) { + clrBody.Set(192, 192, 96, transp[fp]); + clrPad.Set(160, 0, 0, transp[fp]); + clrPadFill.Set(160, 48, 48, transp[fp]); + clrText.Set(240, 240, 64, transp[fp]); + clrHiddenText.Set(160, 160, 50, transp[fp]); + } else { + clrBody.Set(192, 96, 192, transp[fp]); + clrPad.Set(0, 160, 0, transp[fp]); + clrPadFill.Set(48, 160, 48, transp[fp]); + clrText.Set(240, 64, 240, transp[fp]); + clrHiddenText.Set(160, 50, 160, transp[fp]); + } if (OutlineMode) clrBody.Set(80, 80, 80, transp[fp]); - /* Draw the outline, plus optionally the texts */ - pen.SetColour(clrBody); - gc->SetPen(pen); - gc->SetBrush(*wxTRANSPARENT_BRUSH); - bool unit_mm = Footprint[fp].Type >= VER_MM; - double module_angle = 0; /* all angles should be corrected with the footprint angle */ - for (int idx = 0; idx < (int)PartData[fp].Count(); idx++) { - wxString line = PartData[fp][idx]; - wxString token = GetToken(&line); - if (token.CmpNoCase(wxT("Po")) == 0) { - GetToken(&line); /* ignore X position */ - GetToken(&line); /* ignore Y position */ - if (line.length() > 0) - module_angle = GetTokenLong(&line) / 10.0; - } else if (token.CmpNoCase(wxT("DS")) == 0) { - double x1 = GetTokenDim(&line, unit_mm); - double y1 = GetTokenDim(&line, unit_mm); - double x2 = GetTokenDim(&line, unit_mm); - double y2 = GetTokenDim(&line, unit_mm); - double penwidth = GetTokenDim(&line, unit_mm); - /* ignore layer */ - penwidth *= Scale; - if (penwidth < DEFAULTPEN) - penwidth = DEFAULTPEN; - pen.SetWidth(penwidth); - gc->SetPen(pen); - points[0].m_x = x1 * Scale + midx; - points[0].m_y = y1 * Scale + midy; - points[1].m_x = x2 * Scale + midx; - points[1].m_y = y2 * Scale + midy; - gc->DrawLines(2, points); - UpdateBoundingBox(&bbox, x1, y1); - UpdateBoundingBox(&bbox, x2, y2); - } else if (token.CmpNoCase(wxT("DC")) == 0) { - double x = GetTokenDim(&line, unit_mm); - double y = GetTokenDim(&line, unit_mm); - double dx = GetTokenDim(&line, unit_mm); - double dy = GetTokenDim(&line, unit_mm); - double penwidth = GetTokenDim(&line, unit_mm); - /* ignore layer */ - penwidth *= Scale; - if (penwidth < DEFAULTPEN) - penwidth = DEFAULTPEN; - pen.SetWidth(penwidth); - gc->SetPen(pen); - dx -= x; - dy -= y; - double radius = sqrt(dx * dx + dy * dy); - gc->DrawEllipse((x - radius) * Scale + midx, (y - radius) * Scale + midy, - 2 * radius * Scale, 2 * radius * Scale); - UpdateBoundingBox(&bbox, x - radius, y - radius, 2 * radius, 2 * radius); - } else if (token.CmpNoCase(wxT("DA")) == 0) { - double x = GetTokenDim(&line, unit_mm); - double y = GetTokenDim(&line, unit_mm); - double dx = GetTokenDim(&line, unit_mm); - double dy = GetTokenDim(&line, unit_mm); - double angle = GetTokenLong(&line) / 10.0; - double penwidth = GetTokenDim(&line, unit_mm); - /* ignore layer */ - penwidth *= Scale; - if (penwidth < DEFAULTPEN) - penwidth = DEFAULTPEN; - pen.SetWidth(penwidth); - gc->SetPen(pen); - dx -= x; - dy -= y; - double radius = sqrt(dx * dx + dy * dy); - double startangle = atan2(dy, dx); - double endangle = startangle + (double)angle * M_PI / 180.0; - if (endangle > 2 * M_PI) - endangle -= 2 * M_PI; - wxGraphicsPath path = gc->CreatePath(); - path.AddArc(x * Scale + midx, y * Scale + midy, radius * Scale, startangle, endangle, true); - gc->DrawPath(path); - /* for the bounding box, assume that the arc is a circle (the - bounding box does not need to be exact) */ - UpdateBoundingBox(&bbox, x - radius, y - radius, 2 * radius, 2 * radius); - } else if (token.CmpNoCase(wxT("DP")) == 0) { - GetToken(&line); /* ignore first four unknown values */ - GetToken(&line); - GetToken(&line); - GetToken(&line); - long count = GetTokenLong(&line); - wxASSERT(count > 0); - double penwidth = GetTokenDim(&line, unit_mm); - /* ignore layer */ - penwidth *= Scale; - if (penwidth < DEFAULTPEN) - penwidth = DEFAULTPEN; - pen.SetWidth(penwidth); - gc->SetPen(pen); + /* Draw the outline, plus optionally the texts */ + pen.SetColour(clrBody); + gc->SetPen(pen); + gc->SetBrush(*wxTRANSPARENT_BRUSH); + bool unit_mm = Footprint[fp].Type >= VER_MM; + double module_angle = 0; /* all angles should be corrected with the footprint angle */ + for (int idx = 0; idx < (int)PartData[fp].Count(); idx++) { + wxString line = PartData[fp][idx]; + wxString token = GetToken(&line); + if (token.CmpNoCase(wxT("Po")) == 0) { + GetToken(&line); /* ignore X position */ + GetToken(&line); /* ignore Y position */ + if (line.length() > 0) + module_angle = GetTokenLong(&line) / 10.0; + } else if (token.CmpNoCase(wxT("DS")) == 0) { + double x1 = GetTokenDim(&line, unit_mm); + double y1 = GetTokenDim(&line, unit_mm); + double x2 = GetTokenDim(&line, unit_mm); + double y2 = GetTokenDim(&line, unit_mm); + double penwidth = GetTokenDim(&line, unit_mm); + /* ignore layer */ + penwidth *= Scale; + if (penwidth < DEFAULTPEN) + penwidth = DEFAULTPEN; + pen.SetWidth(penwidth); + gc->SetPen(pen); + points[0].m_x = x1 * Scale + midx; + points[0].m_y = y1 * Scale + midy; + points[1].m_x = x2 * Scale + midx; + points[1].m_y = y2 * Scale + midy; + gc->DrawLines(2, points); + UpdateBoundingBox(&bbox, x1, y1); + UpdateBoundingBox(&bbox, x2, y2); + } else if (token.CmpNoCase(wxT("DC")) == 0) { + double x = GetTokenDim(&line, unit_mm); + double y = GetTokenDim(&line, unit_mm); + double dx = GetTokenDim(&line, unit_mm); + double dy = GetTokenDim(&line, unit_mm); + double penwidth = GetTokenDim(&line, unit_mm); + /* ignore layer */ + penwidth *= Scale; + if (penwidth < DEFAULTPEN) + penwidth = DEFAULTPEN; + pen.SetWidth(penwidth); + gc->SetPen(pen); + dx -= x; + dy -= y; + double radius = sqrt(dx * dx + dy * dy); + gc->DrawEllipse((x - radius) * Scale + midx, (y - radius) * Scale + midy, + 2 * radius * Scale, 2 * radius * Scale); + UpdateBoundingBox(&bbox, x - radius, y - radius, 2 * radius, 2 * radius); + } else if (token.CmpNoCase(wxT("DA")) == 0) { + double x = GetTokenDim(&line, unit_mm); + double y = GetTokenDim(&line, unit_mm); + double dx = GetTokenDim(&line, unit_mm); + double dy = GetTokenDim(&line, unit_mm); + double angle = GetTokenLong(&line) / 10.0; + double penwidth = GetTokenDim(&line, unit_mm); + /* ignore layer */ + penwidth *= Scale; + if (penwidth < DEFAULTPEN) + penwidth = DEFAULTPEN; + pen.SetWidth(penwidth); + gc->SetPen(pen); + dx -= x; + dy -= y; + double radius = sqrt(dx * dx + dy * dy); + double startangle = atan2(dy, dx); + double endangle = startangle + (double)angle * M_PI / 180.0; + if (endangle > 2 * M_PI) + endangle -= 2 * M_PI; + wxGraphicsPath path = gc->CreatePath(); + path.AddArc(x * Scale + midx, y * Scale + midy, radius * Scale, startangle, endangle, true); + gc->DrawPath(path); + /* for the bounding box, assume that the arc is a circle (the + bounding box does not need to be exact) */ + UpdateBoundingBox(&bbox, x - radius, y - radius, 2 * radius, 2 * radius); + } else if (token.CmpNoCase(wxT("DP")) == 0) { + GetToken(&line); /* ignore first four unknown values */ + GetToken(&line); + GetToken(&line); + GetToken(&line); + long count = GetTokenLong(&line); + wxASSERT(count > 0); + double penwidth = GetTokenDim(&line, unit_mm); + /* ignore layer */ + penwidth *= Scale; + if (penwidth < DEFAULTPEN) + penwidth = DEFAULTPEN; + pen.SetWidth(penwidth); + gc->SetPen(pen); if (OutlineMode) { gc->SetBrush(*wxTRANSPARENT_BRUSH); } else { - wxBrush brush(clrBody); - gc->SetBrush(brush); + wxBrush brush(clrBody); + gc->SetBrush(brush); } - wxPoint2DDouble *pt = new wxPoint2DDouble[count]; - wxASSERT(pt != NULL); - for (long p = 0; p < count; p++) { - idx++; - line = PartData[fp][idx]; - token = GetToken(&line); - wxASSERT(token.CmpNoCase(wxT("Dl")) == 0); - double x = GetTokenDim(&line, unit_mm); - double y = GetTokenDim(&line, unit_mm); - pt[p].m_x = x * Scale + midx; - pt[p].m_y = y * Scale + midy; - UpdateBoundingBox(&bbox, x, y); - } - gc->DrawLines(count, pt); - gc->SetBrush(*wxTRANSPARENT_BRUSH); - delete[] pt; - } else if (toupper(token[0]) == 'T' && isdigit(token[1])) { - long field; - if (ShowLabels || (token.Mid(1).ToLong(&field) && field >= 2)) { - double x = GetTokenDim(&line, unit_mm); - double y = GetTokenDim(&line, unit_mm); - double cy = GetTokenDim(&line, unit_mm); - double cx = GetTokenDim(&line, unit_mm); - double rot = NormalizeAngle(GetTokenLong(&line) / 10.0 - module_angle); - double penwidth = GetTokenDim(&line, unit_mm); - GetToken(&line); /* ignore mirror flag */ - wxString visflag = GetToken(&line); - bool visible = (visflag == wxT('V')); - GetToken(&line); /* ignore layer */ + wxPoint2DDouble *pt = new wxPoint2DDouble[count]; + wxASSERT(pt != NULL); + for (long p = 0; p < count; p++) { + idx++; + line = PartData[fp][idx]; + token = GetToken(&line); + wxASSERT(token.CmpNoCase(wxT("Dl")) == 0); + double x = GetTokenDim(&line, unit_mm); + double y = GetTokenDim(&line, unit_mm); + pt[p].m_x = x * Scale + midx; + pt[p].m_y = y * Scale + midy; + UpdateBoundingBox(&bbox, x, y); + } + gc->DrawLines(count, pt); + gc->SetBrush(*wxTRANSPARENT_BRUSH); + delete[] pt; + } else if (toupper(token[0]) == 'T' && isdigit(token[1])) { + long field; + if (ShowLabels || (token.Mid(1).ToLong(&field) && field >= 2)) { + double x = GetTokenDim(&line, unit_mm); + double y = GetTokenDim(&line, unit_mm); + double cy = GetTokenDim(&line, unit_mm); + double cx = GetTokenDim(&line, unit_mm); + double rot = NormalizeAngle(GetTokenLong(&line) / 10.0 - module_angle); + double penwidth = GetTokenDim(&line, unit_mm); + GetToken(&line); /* ignore mirror flag */ + wxString visflag = GetToken(&line); + bool visible = (visflag == wxT('V')); + GetToken(&line); /* ignore layer */ bool italic = false; - if (line[0] == '"' || (line.length() > 1 && line[1] == '"')) { - /* the italic flag is absent or it is glued to the text */ - if (line[0] != '"') { + if (line[0] == '"' || (line.length() > 1 && line[1] == '"')) { + /* the italic flag is absent or it is glued to the text */ + if (line[0] != '"') { italic = (token[0] == 'I'); - line = line.Mid(1); + line = line.Mid(1); } - wxASSERT(line[0] == '"'); - token = GetToken(&line); - } else { - token = GetToken(&line); + wxASSERT(line[0] == '"'); + token = GetToken(&line); + } else { + token = GetToken(&line); italic = (token.Length() > 0) && (token[0] == 'I'); - token = GetToken(&line); - } - penwidth *= Scale; - if (penwidth < DEFAULTPEN) - penwidth = DEFAULTPEN; - wxPen tpen; - tpen.SetWidth(penwidth); - tpen.SetColour(visible ? clrText : clrHiddenText); - gc->SetPen(tpen); - VFont.SetScale(cx / CXF_CAPSHEIGHT * Scale, cy / CXF_CAPSHEIGHT * Scale); + token = GetToken(&line); + } + penwidth *= Scale; + if (penwidth < DEFAULTPEN) + penwidth = DEFAULTPEN; + wxPen tpen; + tpen.SetWidth(penwidth); + tpen.SetColour(visible ? clrText : clrHiddenText); + gc->SetPen(tpen); + VFont.SetScale(cx / CXF_CAPSHEIGHT * Scale, cy / CXF_CAPSHEIGHT * Scale); VFont.SetItalic(italic); - VFont.SetOverbar(false); - VFont.SetRotation((int)rot); - VFont.SetAlign(CXF_ALIGNCENTRE, CXF_ALIGNCENTRE); - DrawStrokeText(gc, x * Scale + midx, y * Scale + midy, token); - UpdateBoundingBox(&bbox, x, y); //??? calculate the bounding box of the text - } - } else if (token.Cmp(wxT("(at")) == 0) { - GetToken(&line); /* ignore X */ - GetToken(&line); /* ignore Y */ - if (line.length() > 0) - module_angle = GetTokenDouble(&line); - } else if (token.Cmp(wxT("(fp_line")) == 0) { - double x1=0, y1=0, x2=0, y2=0, penwidth=0; - wxString section = GetSection(line, wxT("start")); - if (section.length() > 0) { - x1 = GetTokenDim(§ion, true); - y1 = GetTokenDim(§ion, true); - } - section = GetSection(line, wxT("end")); - if (section.length() > 0) { - x2 = GetTokenDim(§ion, true); - y2 = GetTokenDim(§ion, true); - } - section = GetSection(line, wxT("width")); - if (section.length() > 0) - penwidth = GetTokenDim(§ion, true); - penwidth *= Scale; - if (penwidth < DEFAULTPEN) - penwidth = DEFAULTPEN; - pen.SetWidth(penwidth); - gc->SetPen(pen); - points[0].m_x = x1 * Scale + midx; - points[0].m_y = y1 * Scale + midy; - points[1].m_x = x2 * Scale + midx; - points[1].m_y = y2 * Scale + midy; - gc->DrawLines(2, points); - UpdateBoundingBox(&bbox, x1, y1); - UpdateBoundingBox(&bbox, x2, y2); - } else if (token.Cmp(wxT("(fp_circle")) == 0) { - double x=0, y=0, dx=0, dy=0, penwidth=0; - wxString section = GetSection(line, wxT("center")); - if (section.length() > 0) { - x = GetTokenDim(§ion, true); - y = GetTokenDim(§ion, true); - } - section = GetSection(line, wxT("end")); - if (section.length() > 0) { - dx = GetTokenDim(§ion, true); - dy = GetTokenDim(§ion, true); - } - section = GetSection(line, wxT("width")); - if (section.length() > 0) - penwidth = GetTokenDim(§ion, true); - penwidth *= Scale; - if (penwidth < DEFAULTPEN) - penwidth = DEFAULTPEN; - pen.SetWidth(penwidth); - gc->SetPen(pen); - dx -= x; - dy -= y; - double radius = sqrt(dx * dx + dy * dy); - gc->DrawEllipse((x - radius) * Scale + midx, (y - radius) * Scale + midy, - 2 * radius * Scale, 2 * radius * Scale); - UpdateBoundingBox(&bbox, x - radius, y - radius, 2 * radius, 2 * radius); - } else if (token.Cmp(wxT("(fp_arc")) == 0) { - double x=0, y=0, dx=0, dy=0, penwidth=0; - double angle = 0; - wxString section = GetSection(line, wxT("start")); - if (section.length() > 0) { - x = GetTokenDim(§ion, true); - y = GetTokenDim(§ion, true); - } - section = GetSection(line, wxT("end")); - if (section.length() > 0) { - dx = GetTokenDim(§ion, true); - dy = GetTokenDim(§ion, true); - } - section = GetSection(line, wxT("angle")); - if (section.length() > 0) - angle = GetTokenDouble(§ion); - section = GetSection(line, wxT("width")); - if (section.length() > 0) - penwidth = GetTokenDim(§ion, true); - penwidth *= Scale; - if (penwidth < DEFAULTPEN) - penwidth = DEFAULTPEN; - pen.SetWidth(penwidth); - gc->SetPen(pen); - dx -= x; - dy -= y; - double radius = sqrt(dx * dx + dy * dy); - double startangle = atan2(dy, dx); - double endangle = startangle + (double)angle * M_PI / 180.0; - if (endangle > 2 * M_PI) - endangle -= 2 * M_PI; - wxGraphicsPath path = gc->CreatePath(); - path.AddArc(x * Scale + midx, y * Scale + midy, radius * Scale, startangle, endangle, true); - gc->DrawPath(path); - /* for the bounding box, assume that the arc is a circle (the - bounding box does not need to be exact) */ - UpdateBoundingBox(&bbox, x - radius, y - radius, 2 * radius, 2 * radius); - } else if (token.Cmp(wxT("(fp_poly")) == 0) { - double penwidth = 0; - wxString section = GetSection(line, wxT("width")); - if (section.length() > 0) - penwidth = GetTokenDim(§ion, true); - penwidth *= Scale; - if (penwidth < DEFAULTPEN) - penwidth = DEFAULTPEN; - pen.SetWidth(penwidth); - gc->SetPen(pen); + VFont.SetOverbar(false); + VFont.SetRotation((int)rot); + VFont.SetAlign(CXF_ALIGNCENTRE, CXF_ALIGNCENTRE); + DrawStrokeText(gc, x * Scale + midx, y * Scale + midy, token); + UpdateBoundingBox(&bbox, x, y); //??? calculate the bounding box of the text + } + } else if (token.Cmp(wxT("(at")) == 0) { + GetToken(&line); /* ignore X */ + GetToken(&line); /* ignore Y */ + if (line.length() > 0) + module_angle = GetTokenDouble(&line); + } else if (token.Cmp(wxT("(fp_line")) == 0) { + double x1=0, y1=0, x2=0, y2=0, penwidth=0; + wxString section = GetSection(line, wxT("start")); + if (section.length() > 0) { + x1 = GetTokenDim(§ion, true); + y1 = GetTokenDim(§ion, true); + } + section = GetSection(line, wxT("end")); + if (section.length() > 0) { + x2 = GetTokenDim(§ion, true); + y2 = GetTokenDim(§ion, true); + } + section = GetSection(line, wxT("width")); + if (section.length() > 0) + penwidth = GetTokenDim(§ion, true); + penwidth *= Scale; + if (penwidth < DEFAULTPEN) + penwidth = DEFAULTPEN; + pen.SetWidth(penwidth); + gc->SetPen(pen); + points[0].m_x = x1 * Scale + midx; + points[0].m_y = y1 * Scale + midy; + points[1].m_x = x2 * Scale + midx; + points[1].m_y = y2 * Scale + midy; + gc->DrawLines(2, points); + UpdateBoundingBox(&bbox, x1, y1); + UpdateBoundingBox(&bbox, x2, y2); + } else if (token.Cmp(wxT("(fp_circle")) == 0) { + double x=0, y=0, dx=0, dy=0, penwidth=0; + wxString section = GetSection(line, wxT("center")); + if (section.length() > 0) { + x = GetTokenDim(§ion, true); + y = GetTokenDim(§ion, true); + } + section = GetSection(line, wxT("end")); + if (section.length() > 0) { + dx = GetTokenDim(§ion, true); + dy = GetTokenDim(§ion, true); + } + section = GetSection(line, wxT("width")); + if (section.length() > 0) + penwidth = GetTokenDim(§ion, true); + penwidth *= Scale; + if (penwidth < DEFAULTPEN) + penwidth = DEFAULTPEN; + pen.SetWidth(penwidth); + gc->SetPen(pen); + dx -= x; + dy -= y; + double radius = sqrt(dx * dx + dy * dy); + gc->DrawEllipse((x - radius) * Scale + midx, (y - radius) * Scale + midy, + 2 * radius * Scale, 2 * radius * Scale); + UpdateBoundingBox(&bbox, x - radius, y - radius, 2 * radius, 2 * radius); + } else if (token.Cmp(wxT("(fp_arc")) == 0) { + double x=0, y=0, dx=0, dy=0, penwidth=0; + double angle = 0; + wxString section = GetSection(line, wxT("start")); + if (section.length() > 0) { + x = GetTokenDim(§ion, true); + y = GetTokenDim(§ion, true); + } + section = GetSection(line, wxT("end")); + if (section.length() > 0) { + dx = GetTokenDim(§ion, true); + dy = GetTokenDim(§ion, true); + } + section = GetSection(line, wxT("angle")); + if (section.length() > 0) + angle = GetTokenDouble(§ion); + section = GetSection(line, wxT("width")); + if (section.length() > 0) + penwidth = GetTokenDim(§ion, true); + penwidth *= Scale; + if (penwidth < DEFAULTPEN) + penwidth = DEFAULTPEN; + pen.SetWidth(penwidth); + gc->SetPen(pen); + dx -= x; + dy -= y; + double radius = sqrt(dx * dx + dy * dy); + double startangle = atan2(dy, dx); + double endangle = startangle + (double)angle * M_PI / 180.0; + if (endangle > 2 * M_PI) + endangle -= 2 * M_PI; + wxGraphicsPath path = gc->CreatePath(); + path.AddArc(x * Scale + midx, y * Scale + midy, radius * Scale, startangle, endangle, true); + gc->DrawPath(path); + /* for the bounding box, assume that the arc is a circle (the + bounding box does not need to be exact) */ + UpdateBoundingBox(&bbox, x - radius, y - radius, 2 * radius, 2 * radius); + } else if (token.Cmp(wxT("(fp_poly")) == 0) { + double penwidth = 0; + wxString section = GetSection(line, wxT("width")); + if (section.length() > 0) + penwidth = GetTokenDim(§ion, true); + penwidth *= Scale; + if (penwidth < DEFAULTPEN) + penwidth = DEFAULTPEN; + pen.SetWidth(penwidth); + gc->SetPen(pen); if (OutlineMode) { gc->SetBrush(*wxTRANSPARENT_BRUSH); } else { - wxBrush brush(clrBody); - gc->SetBrush(brush); + wxBrush brush(clrBody); + gc->SetBrush(brush); } - /* first count the number of vertices */ - section = GetSection(line, wxT("pts")); - long count = 0; - while (GetSection(section, wxT("xy"), count).Length() > 0) - count++; - wxPoint2DDouble *pt = new wxPoint2DDouble[count]; - wxASSERT(pt != NULL); - for (long p = 0; p < count; p++) { - wxString subsect = GetSection(section, wxT("xy"), p); - wxASSERT(subsect.length() > 0); - double x = GetTokenDim(&subsect, true); - double y = GetTokenDim(&subsect, true); - pt[p].m_x = x * Scale + midx; - pt[p].m_y = y * Scale + midy; - UpdateBoundingBox(&bbox, x, y); - } - gc->DrawLines(count, pt); - gc->SetBrush(*wxTRANSPARENT_BRUSH); - delete[] pt; - } else if (token.Cmp(wxT("(fp_text")) == 0) { - wxString ident = GetToken(&line); - if (ShowLabels || ident.Cmp(wxT("user")) == 0) { - double x = 0, y = 0, cx = 0, cy = 0, penwidth = 1; - double rot = 0; - token = GetToken(&line); /* get the text itself */ - bool visible = line.Find(wxT(" hide ")) == wxNOT_FOUND; - wxString section = GetSection(line, wxT("at")); - if (section.length() > 0) { - x = GetTokenDim(§ion, true); - y = GetTokenDim(§ion, true); - if (section.length() > 0) - rot = NormalizeAngle(GetTokenDouble(§ion) - module_angle); - } - section = GetSection(line, wxT("effects")); - if (section.length() > 0) { - section = GetSection(section, wxT("font")); - if (section.length() > 0) { - wxString subsect = GetSection(section, wxT("size")); - if (subsect.length() > 0) { - cy = GetTokenDim(&subsect, true); - cx = GetTokenDim(&subsect, true); - } - subsect = GetSection(section, wxT("thickness")); - if (subsect.length() > 0) - penwidth = GetTokenDim(&subsect, true); - } - } - penwidth *= Scale; - if (penwidth < DEFAULTPEN) - penwidth = DEFAULTPEN; - wxPen tpen; - tpen.SetWidth(penwidth); - tpen.SetColour(visible ? clrText : clrHiddenText); - gc->SetPen(tpen); - VFont.SetScale(cx / CXF_CAPSHEIGHT * Scale, cy / CXF_CAPSHEIGHT * Scale); - VFont.SetOverbar(false); - VFont.SetRotation((int)rot); - VFont.SetAlign(CXF_ALIGNCENTRE, CXF_ALIGNCENTRE); - DrawStrokeText(gc, x * Scale + midx, y * Scale + midy, token); - UpdateBoundingBox(&bbox, x, y); //??? calculate the bounding box of the text - } - } - } - - /* draw the pads */ - wxBrush brush; + /* first count the number of vertices */ + section = GetSection(line, wxT("pts")); + long count = 0; + while (GetSection(section, wxT("xy"), count).Length() > 0) + count++; + wxPoint2DDouble *pt = new wxPoint2DDouble[count]; + wxASSERT(pt != NULL); + for (long p = 0; p < count; p++) { + wxString subsect = GetSection(section, wxT("xy"), p); + wxASSERT(subsect.length() > 0); + double x = GetTokenDim(&subsect, true); + double y = GetTokenDim(&subsect, true); + pt[p].m_x = x * Scale + midx; + pt[p].m_y = y * Scale + midy; + UpdateBoundingBox(&bbox, x, y); + } + gc->DrawLines(count, pt); + gc->SetBrush(*wxTRANSPARENT_BRUSH); + delete[] pt; + } else if (token.Cmp(wxT("(fp_text")) == 0) { + wxString ident = GetToken(&line); + if (ShowLabels || ident.Cmp(wxT("user")) == 0) { + double x = 0, y = 0, cx = 0, cy = 0, penwidth = 1; + double rot = 0; + token = GetToken(&line); /* get the text itself */ + bool visible = line.Find(wxT(" hide ")) == wxNOT_FOUND; + wxString section = GetSection(line, wxT("at")); + if (section.length() > 0) { + x = GetTokenDim(§ion, true); + y = GetTokenDim(§ion, true); + if (section.length() > 0) + rot = NormalizeAngle(GetTokenDouble(§ion) - module_angle); + } + section = GetSection(line, wxT("effects")); + if (section.length() > 0) { + section = GetSection(section, wxT("font")); + if (section.length() > 0) { + wxString subsect = GetSection(section, wxT("size")); + if (subsect.length() > 0) { + cy = GetTokenDim(&subsect, true); + cx = GetTokenDim(&subsect, true); + } + subsect = GetSection(section, wxT("thickness")); + if (subsect.length() > 0) + penwidth = GetTokenDim(&subsect, true); + } + } + penwidth *= Scale; + if (penwidth < DEFAULTPEN) + penwidth = DEFAULTPEN; + wxPen tpen; + tpen.SetWidth(penwidth); + tpen.SetColour(visible ? clrText : clrHiddenText); + gc->SetPen(tpen); + VFont.SetScale(cx / CXF_CAPSHEIGHT * Scale, cy / CXF_CAPSHEIGHT * Scale); + VFont.SetOverbar(false); + VFont.SetRotation((int)rot); + VFont.SetAlign(CXF_ALIGNCENTRE, CXF_ALIGNCENTRE); + DrawStrokeText(gc, x * Scale + midx, y * Scale + midy, token); + UpdateBoundingBox(&bbox, x, y); //??? calculate the bounding box of the text + } + } + } + + /* draw the pads */ + wxBrush brush; wxPen pen; if (OutlineMode) { brush = *wxTRANSPARENT_BRUSH; - pen.SetColour(clrPad); + pen.SetColour(clrPad); pen.SetWidth(0.2 * Scale); } else { - brush.SetColour(clrPadFill); + brush.SetColour(clrPadFill); brush.SetStyle(wxBRUSHSTYLE_SOLID); - pen.SetColour(clrPad); - pen.SetWidth(1); + pen.SetColour(clrPad); + pen.SetWidth(1); } - gc->SetBrush(brush); - gc->SetPen(pen); + gc->SetBrush(brush); + gc->SetPen(pen); - wxBrush brushHole; - brushHole.SetColour(wxColour(224, 224, 0, transp[fp])); + wxBrush brushHole; + brushHole.SetColour(wxColour(224, 224, 0, transp[fp])); - wxFont font(FontSizeLegend, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD); - font.SetPointSize(FontSizeLegend); - gc->SetFont(font, clrHiddenText); + wxFont font(FontSizeLegend, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD); + font.SetPointSize(FontSizeLegend); + gc->SetFont(font, clrHiddenText); - bool inpad = false; - double padx = 0, pady = 0, padwidth = 0, padheight = 0, padrot = 0; - double paddeltax = 0, paddeltay = 0; - double drillx = 0, drilly = 0, drillwidth = 0, drillheight = 0; + bool inpad = false; + double padx = 0, pady = 0, padwidth = 0, padheight = 0, padrot = 0; + double paddeltax = 0, paddeltay = 0; + double drillx = 0, drilly = 0, drillwidth = 0, drillheight = 0; double pasteratio = 0.0; wxPoint2DDouble pastepoints[5]; - wxString padpin, padshape; - for (int idx = 0; idx < (int)PartData[fp].Count(); idx++) { - wxString line = PartData[fp][idx]; - if (line[0] == wxT('$')) { - if (line.CmpNoCase(wxT("$PAD")) == 0) { - inpad = true; - drillwidth = drillheight = 0; + wxString padpin, padshape; + for (int idx = 0; idx < (int)PartData[fp].Count(); idx++) { + wxString line = PartData[fp][idx]; + if (line[0] == wxT('$')) { + if (line.CmpNoCase(wxT("$PAD")) == 0) { + inpad = true; + drillwidth = drillheight = 0; pasteratio = 0.0; - } else if (line.CmpNoCase(wxT("$EndPAD")) == 0) { + } else if (line.CmpNoCase(wxT("$EndPAD")) == 0) { /* make the pad smaller in outline mode */ if (OutlineMode) { - if (padwidth > 0.3) + if (padwidth > 0.3) padwidth -= 0.15; - if (padheight > 0.3) + if (padheight > 0.3) padheight -= 0.15; } - /* draw the pad */ - points[0].m_x = -padwidth/2 * Scale; - points[0].m_y = -padheight/2 * Scale; - points[1].m_x = padwidth/2 * Scale; - points[1].m_y = -padheight/2 * Scale; - points[2].m_x = padwidth/2 * Scale; - points[2].m_y = padheight/2 * Scale; - points[3].m_x = -padwidth/2 * Scale; - points[3].m_y = padheight/2 * Scale; - points[4] = points[0]; - if (padshape.CmpNoCase(wxT("T")) == 0) { - if (!Equal(paddeltax, 0.0)) { - points[0].m_y -= paddeltax * Scale / 2; - points[1].m_y += paddeltax * Scale / 2; - points[2].m_y -= paddeltax * Scale / 2; - points[3].m_y += paddeltax * Scale / 2; - } - if (!Equal(paddeltay, 0.0)) { - points[0].m_x += paddeltay * Scale / 2; - points[1].m_x -= paddeltay * Scale / 2; - points[2].m_x += paddeltay * Scale / 2; - points[3].m_x -= paddeltay * Scale / 2; - } - } - points[4] = points[0]; + /* draw the pad */ + points[0].m_x = -padwidth/2 * Scale; + points[0].m_y = -padheight/2 * Scale; + points[1].m_x = padwidth/2 * Scale; + points[1].m_y = -padheight/2 * Scale; + points[2].m_x = padwidth/2 * Scale; + points[2].m_y = padheight/2 * Scale; + points[3].m_x = -padwidth/2 * Scale; + points[3].m_y = padheight/2 * Scale; + points[4] = points[0]; + if (padshape.CmpNoCase(wxT("T")) == 0) { + if (!Equal(paddeltax, 0.0)) { + points[0].m_y -= paddeltax * Scale / 2; + points[1].m_y += paddeltax * Scale / 2; + points[2].m_y -= paddeltax * Scale / 2; + points[3].m_y += paddeltax * Scale / 2; + } + if (!Equal(paddeltay, 0.0)) { + points[0].m_x += paddeltay * Scale / 2; + points[1].m_x -= paddeltay * Scale / 2; + points[2].m_x += paddeltay * Scale / 2; + points[3].m_x -= paddeltay * Scale / 2; + } + } + points[4] = points[0]; /* make scaled pad for paste */ memcpy(pastepoints, points, sizeof pastepoints); if (pasteratio < -EPSILON && pasteratio > -0.5 && !OutlineMode) { @@ -3184,164 +3185,164 @@ void libmngrFrame::DrawFootprints(wxGraphicsContext *gc, int midx, int midy, con pastepoints[2].m_y = points[2].m_y + d * pasteratio; pastepoints[4] = pastepoints[0]; } - /* apply rotation */ - if (padrot > EPSILON) { - double angle = (padrot * M_PI / 180.0); - for (int idx = 0; idx < 5; idx++) { - wxDouble nx = points[idx].m_x * cos(angle) - points[idx].m_y * sin(angle); - wxDouble ny = points[idx].m_x * sin(angle) + points[idx].m_y * cos(angle); - points[idx].m_x = nx; - points[idx].m_y = ny; + /* apply rotation */ + if (padrot > EPSILON) { + double angle = (padrot * M_PI / 180.0); + for (int idx = 0; idx < 5; idx++) { + wxDouble nx = points[idx].m_x * cos(angle) - points[idx].m_y * sin(angle); + wxDouble ny = points[idx].m_x * sin(angle) + points[idx].m_y * cos(angle); + points[idx].m_x = nx; + points[idx].m_y = ny; /* same for paste aperture */ - nx = pastepoints[idx].m_x * cos(angle) - pastepoints[idx].m_y * sin(angle); - ny = pastepoints[idx].m_x * sin(angle) + pastepoints[idx].m_y * cos(angle); - pastepoints[idx].m_x = nx; - pastepoints[idx].m_y = ny; - } - } - /* move pad relative to footprint origin */ - for (int idx = 0; idx < 5; idx++) { - points[idx].m_x += padx * Scale + midx; - points[idx].m_y += pady * Scale + midy; - UpdateBoundingBox(&bbox, padx, pady); - pastepoints[idx].m_x += padx * Scale + midx; - pastepoints[idx].m_y += pady * Scale + midy; - } - gc->SetBrush(brush); - /* avoid negative width/height for ellipses or obrounds */ - CoordSize cs(points[0].m_x, points[0].m_y, points[2].m_x - points[0].m_x, points[2].m_y - points[0].m_y); - if (padshape.CmpNoCase(wxT("C")) == 0) - gc->DrawEllipse(cs.GetX(), cs.GetY(), cs.GetWidth(), cs.GetHeight()); - else if (padshape.CmpNoCase(wxT("O")) == 0) - gc->DrawRoundedRectangle(cs.GetX(), cs.GetY(), cs.GetWidth(), cs.GetHeight(), - ((cs.GetWidth() < cs.GetHeight()) ? cs.GetWidth() : cs.GetHeight()) / 2); - else - gc->DrawLines(5, points); + nx = pastepoints[idx].m_x * cos(angle) - pastepoints[idx].m_y * sin(angle); + ny = pastepoints[idx].m_x * sin(angle) + pastepoints[idx].m_y * cos(angle); + pastepoints[idx].m_x = nx; + pastepoints[idx].m_y = ny; + } + } + /* move pad relative to footprint origin */ + for (int idx = 0; idx < 5; idx++) { + points[idx].m_x += padx * Scale + midx; + points[idx].m_y += pady * Scale + midy; + UpdateBoundingBox(&bbox, padx, pady); + pastepoints[idx].m_x += padx * Scale + midx; + pastepoints[idx].m_y += pady * Scale + midy; + } + gc->SetBrush(brush); + /* avoid negative width/height for ellipses or obrounds */ + CoordSize cs(points[0].m_x, points[0].m_y, points[2].m_x - points[0].m_x, points[2].m_y - points[0].m_y); + if (padshape.CmpNoCase(wxT("C")) == 0) + gc->DrawEllipse(cs.GetX(), cs.GetY(), cs.GetWidth(), cs.GetHeight()); + else if (padshape.CmpNoCase(wxT("O")) == 0) + gc->DrawRoundedRectangle(cs.GetX(), cs.GetY(), cs.GetWidth(), cs.GetHeight(), + ((cs.GetWidth() < cs.GetHeight()) ? cs.GetWidth() : cs.GetHeight()) / 2); + else + gc->DrawLines(5, points); /* draw solder paste ratio, if set */ if (pasteratio < -EPSILON && pasteratio > -0.5 && !OutlineMode) { wxPen pastepen(wxColour(160,160,80), 1, wxPENSTYLE_DOT); gc->SetPen(pastepen); wxBrush pastebrush(wxColour(160,160,80), wxBRUSHSTYLE_FDIAGONAL_HATCH); - gc->SetBrush(pastebrush); - /* avoid negative width/height for ellipses or obrounds */ - cs.Set(pastepoints[0].m_x, pastepoints[0].m_y, pastepoints[2].m_x - pastepoints[0].m_x, pastepoints[2].m_y - pastepoints[0].m_y); - if (padshape.CmpNoCase(wxT("C")) == 0) - gc->DrawEllipse(cs.GetX(), cs.GetY(), cs.GetWidth(), cs.GetHeight()); - else if (padshape.CmpNoCase(wxT("O")) == 0) - gc->DrawRoundedRectangle(cs.GetX(), cs.GetY(), cs.GetWidth(), cs.GetHeight(), - ((cs.GetWidth() < cs.GetHeight()) ? cs.GetWidth() : cs.GetHeight()) / 2); - else - gc->DrawLines(5, pastepoints); + gc->SetBrush(pastebrush); + /* avoid negative width/height for ellipses or obrounds */ + cs.Set(pastepoints[0].m_x, pastepoints[0].m_y, pastepoints[2].m_x - pastepoints[0].m_x, pastepoints[2].m_y - pastepoints[0].m_y); + if (padshape.CmpNoCase(wxT("C")) == 0) + gc->DrawEllipse(cs.GetX(), cs.GetY(), cs.GetWidth(), cs.GetHeight()); + else if (padshape.CmpNoCase(wxT("O")) == 0) + gc->DrawRoundedRectangle(cs.GetX(), cs.GetY(), cs.GetWidth(), cs.GetHeight(), + ((cs.GetWidth() < cs.GetHeight()) ? cs.GetWidth() : cs.GetHeight()) / 2); + else + gc->DrawLines(5, pastepoints); gc->SetPen(pen); gc->SetBrush(brush); } - /* optionally the hole in the pad */ - if (drillwidth > EPSILON) { - if (padshape == wxT('C') && padwidth - drillwidth < 0.05) - gc->SetBrush(brushHole); - else - gc->SetBrush(*wxBLACK_BRUSH); - if (drillheight > EPSILON) { - if ((padrot > 45 && padrot < 135) || (padrot > 225 && padrot < 315)) { - double t = drillwidth; - drillwidth = drillheight; - drillheight = t; - } - cs.Set((padx + drillx - drillwidth/2) * Scale + midx, - (pady + drilly - drillheight/2) * Scale + midy, - drillwidth * Scale, drillheight * Scale); - gc->DrawRoundedRectangle(cs.GetX(), cs.GetY(), cs.GetWidth(), cs.GetHeight(), - ((cs.GetWidth() < cs.GetHeight()) ? cs.GetWidth() : cs.GetHeight()) / 2); - } else { - gc->DrawEllipse((padx + drillx - drillwidth/2) * Scale + midx, - (pady + drilly - drillwidth/2) * Scale + midy, - drillwidth * Scale, drillwidth * Scale); - } - } - /* draw the pin name inside the pad */ - if (ShowPinNumbers) { - wxDouble tw, th, td, tex; - gc->GetTextExtent(padpin, &tw, &th, &td, &tex); - gc->DrawText(padpin, padx * Scale + midx - tw/2, pady * Scale + midy - th/2); - } - inpad = false; - } - continue; - } else if (line[0] == wxT('(') && line.Left(4).Cmp(wxT("(pad")) == 0) { - GetToken(&line); /* ignore "(pad" */ - padpin = GetToken(&line); - GetToken(&line); /* ignore smd/thru_hole/np_thru_hole type */ - padshape = GetToken(&line); - padrot = 0; /* preset pad rotation (frequently omitted) */ - wxString section = GetSection(line, wxT("at")); - if (section.length() > 0) { - padx = GetTokenDim(§ion, true); - pady = GetTokenDim(§ion, true); - if (section.length() > 0) - padrot = NormalizeAngle(GetTokenDouble(§ion) - module_angle); - } - section = GetSection(line, wxT("size")); - if (section.length() > 0) { - padwidth = GetTokenDim(§ion, true); - padheight = GetTokenDim(§ion, true); - } - drillx = drilly = 0; /* preset drill parameters (as these are optional) */ - drillwidth = drillheight = 0; - section = GetSection(line, wxT("drill")); - if (section.length() > 0) { - wxString sectoffset = GetSection(section, wxT("offset")); - if (section.Left(4).Cmp(wxT("oval"))==0) { - GetToken(§ion); - drillwidth = GetTokenDim(§ion, true); - drillheight = GetTokenDim(§ion, true); - } else { - drillwidth = GetTokenDim(§ion, true); - } - if (sectoffset.length() > 0) { - drillx = GetTokenDim(§offset, true); - drilly = GetTokenDim(§offset, true); - } - } - section = GetSection(line, wxT("solder_paste_margin_ratio")); - if (section.length() > 0) - pasteratio = GetTokenDouble(§ion); + /* optionally the hole in the pad */ + if (drillwidth > EPSILON) { + if (padshape == wxT('C') && padwidth - drillwidth < 0.05) + gc->SetBrush(brushHole); + else + gc->SetBrush(*wxBLACK_BRUSH); + if (drillheight > EPSILON) { + if ((padrot > 45 && padrot < 135) || (padrot > 225 && padrot < 315)) { + double t = drillwidth; + drillwidth = drillheight; + drillheight = t; + } + cs.Set((padx + drillx - drillwidth/2) * Scale + midx, + (pady + drilly - drillheight/2) * Scale + midy, + drillwidth * Scale, drillheight * Scale); + gc->DrawRoundedRectangle(cs.GetX(), cs.GetY(), cs.GetWidth(), cs.GetHeight(), + ((cs.GetWidth() < cs.GetHeight()) ? cs.GetWidth() : cs.GetHeight()) / 2); + } else { + gc->DrawEllipse((padx + drillx - drillwidth/2) * Scale + midx, + (pady + drilly - drillwidth/2) * Scale + midy, + drillwidth * Scale, drillwidth * Scale); + } + } + /* draw the pin name inside the pad */ + if (ShowPinNumbers) { + wxDouble tw, th, td, tex; + gc->GetTextExtent(padpin, &tw, &th, &td, &tex); + gc->DrawText(padpin, padx * Scale + midx - tw/2, pady * Scale + midy - th/2); + } + inpad = false; + } + continue; + } else if (line[0] == wxT('(') && line.Left(4).Cmp(wxT("(pad")) == 0) { + GetToken(&line); /* ignore "(pad" */ + padpin = GetToken(&line); + GetToken(&line); /* ignore smd/thru_hole/np_thru_hole type */ + padshape = GetToken(&line); + padrot = 0; /* preset pad rotation (frequently omitted) */ + wxString section = GetSection(line, wxT("at")); + if (section.length() > 0) { + padx = GetTokenDim(§ion, true); + pady = GetTokenDim(§ion, true); + if (section.length() > 0) + padrot = NormalizeAngle(GetTokenDouble(§ion) - module_angle); + } + section = GetSection(line, wxT("size")); + if (section.length() > 0) { + padwidth = GetTokenDim(§ion, true); + padheight = GetTokenDim(§ion, true); + } + drillx = drilly = 0; /* preset drill parameters (as these are optional) */ + drillwidth = drillheight = 0; + section = GetSection(line, wxT("drill")); + if (section.length() > 0) { + wxString sectoffset = GetSection(section, wxT("offset")); + if (section.Left(4).Cmp(wxT("oval"))==0) { + GetToken(§ion); + drillwidth = GetTokenDim(§ion, true); + drillheight = GetTokenDim(§ion, true); + } else { + drillwidth = GetTokenDim(§ion, true); + } + if (sectoffset.length() > 0) { + drillx = GetTokenDim(§offset, true); + drilly = GetTokenDim(§offset, true); + } + } + section = GetSection(line, wxT("solder_paste_margin_ratio")); + if (section.length() > 0) + pasteratio = GetTokenDouble(§ion); else pasteratio = 0.0; if (OutlineMode) { - if (padwidth > 0.3) + if (padwidth > 0.3) padwidth -= 0.15; - if (padheight > 0.3) + if (padheight > 0.3) padheight -= 0.15; } - /* draw the pad */ - points[0].m_x = -padwidth/2 * Scale; - points[0].m_y = -padheight/2 * Scale; - points[1].m_x = padwidth/2 * Scale; - points[1].m_y = -padheight/2 * Scale; - points[2].m_x = padwidth/2 * Scale; - points[2].m_y = padheight/2 * Scale; - points[3].m_x = -padwidth/2 * Scale; - points[3].m_y = padheight/2 * Scale; - if (padshape.Cmp(wxT("trapezoid")) == 0) { - section = GetSection(line, wxT("rect_delta")); - if (section.length() > 0) { - paddeltax = GetTokenDim(§ion, true); - paddeltay = GetTokenDim(§ion, true); - if (!Equal(paddeltax, 0.0)) { - points[0].m_y -= paddeltax * Scale / 2; - points[1].m_y += paddeltax * Scale / 2; - points[2].m_y -= paddeltax * Scale / 2; - points[3].m_y += paddeltax * Scale / 2; - } - if (!Equal(paddeltay, 0.0)) { - points[0].m_x += paddeltay * Scale / 2; - points[1].m_x -= paddeltay * Scale / 2; - points[2].m_x += paddeltay * Scale / 2; - points[3].m_x -= paddeltay * Scale / 2; - } - } - } - points[4] = points[0]; + /* draw the pad */ + points[0].m_x = -padwidth/2 * Scale; + points[0].m_y = -padheight/2 * Scale; + points[1].m_x = padwidth/2 * Scale; + points[1].m_y = -padheight/2 * Scale; + points[2].m_x = padwidth/2 * Scale; + points[2].m_y = padheight/2 * Scale; + points[3].m_x = -padwidth/2 * Scale; + points[3].m_y = padheight/2 * Scale; + if (padshape.Cmp(wxT("trapezoid")) == 0) { + section = GetSection(line, wxT("rect_delta")); + if (section.length() > 0) { + paddeltax = GetTokenDim(§ion, true); + paddeltay = GetTokenDim(§ion, true); + if (!Equal(paddeltax, 0.0)) { + points[0].m_y -= paddeltax * Scale / 2; + points[1].m_y += paddeltax * Scale / 2; + points[2].m_y -= paddeltax * Scale / 2; + points[3].m_y += paddeltax * Scale / 2; + } + if (!Equal(paddeltay, 0.0)) { + points[0].m_x += paddeltay * Scale / 2; + points[1].m_x -= paddeltay * Scale / 2; + points[2].m_x += paddeltay * Scale / 2; + points[3].m_x -= paddeltay * Scale / 2; + } + } + } + points[4] = points[0]; /* make scaled pad for paste */ memcpy(pastepoints, points, sizeof pastepoints); if (pasteratio < -EPSILON && pasteratio > -0.5 && !OutlineMode) { @@ -3360,312 +3361,312 @@ void libmngrFrame::DrawFootprints(wxGraphicsContext *gc, int midx, int midy, con pastepoints[2].m_y = points[2].m_y + d * pasteratio; pastepoints[4] = pastepoints[0]; } - /* apply rotation */ - if (padrot != 0) { - double angle = (padrot * M_PI / 180.0); - for (int idx = 0; idx < 5; idx++) { - wxDouble nx = points[idx].m_x * cos(angle) - points[idx].m_y * sin(angle); - wxDouble ny = points[idx].m_x * sin(angle) + points[idx].m_y * cos(angle); - points[idx].m_x = nx; - points[idx].m_y = ny; + /* apply rotation */ + if (padrot != 0) { + double angle = (padrot * M_PI / 180.0); + for (int idx = 0; idx < 5; idx++) { + wxDouble nx = points[idx].m_x * cos(angle) - points[idx].m_y * sin(angle); + wxDouble ny = points[idx].m_x * sin(angle) + points[idx].m_y * cos(angle); + points[idx].m_x = nx; + points[idx].m_y = ny; /* same for paste aperture */ - nx = pastepoints[idx].m_x * cos(angle) - pastepoints[idx].m_y * sin(angle); - ny = pastepoints[idx].m_x * sin(angle) + pastepoints[idx].m_y * cos(angle); - pastepoints[idx].m_x = nx; - pastepoints[idx].m_y = ny; - } - } - /* move pad relative to footprint origin */ - for (int idx = 0; idx < 5; idx++) { - points[idx].m_x += padx * Scale + midx; - points[idx].m_y += pady * Scale + midy; - UpdateBoundingBox(&bbox, padx, pady); - pastepoints[idx].m_x += padx * Scale + midx; - pastepoints[idx].m_y += pady * Scale + midy; - } - gc->SetBrush(brush); - CoordSize cs(points[0].m_x, points[0].m_y, points[2].m_x - points[0].m_x, points[2].m_y - points[0].m_y); - if (padshape.Cmp(wxT("circle")) == 0) - gc->DrawEllipse(cs.GetX(), cs.GetY(), cs.GetWidth(), cs.GetHeight()); - else if (padshape.Cmp(wxT("oval")) == 0) - gc->DrawRoundedRectangle(cs.GetX(), cs.GetY(), cs.GetWidth(), cs.GetHeight(), - ((cs.GetWidth() < cs.GetHeight()) ? cs.GetWidth() : cs.GetHeight()) / 2); - else - gc->DrawLines(5, points); + nx = pastepoints[idx].m_x * cos(angle) - pastepoints[idx].m_y * sin(angle); + ny = pastepoints[idx].m_x * sin(angle) + pastepoints[idx].m_y * cos(angle); + pastepoints[idx].m_x = nx; + pastepoints[idx].m_y = ny; + } + } + /* move pad relative to footprint origin */ + for (int idx = 0; idx < 5; idx++) { + points[idx].m_x += padx * Scale + midx; + points[idx].m_y += pady * Scale + midy; + UpdateBoundingBox(&bbox, padx, pady); + pastepoints[idx].m_x += padx * Scale + midx; + pastepoints[idx].m_y += pady * Scale + midy; + } + gc->SetBrush(brush); + CoordSize cs(points[0].m_x, points[0].m_y, points[2].m_x - points[0].m_x, points[2].m_y - points[0].m_y); + if (padshape.Cmp(wxT("circle")) == 0) + gc->DrawEllipse(cs.GetX(), cs.GetY(), cs.GetWidth(), cs.GetHeight()); + else if (padshape.Cmp(wxT("oval")) == 0) + gc->DrawRoundedRectangle(cs.GetX(), cs.GetY(), cs.GetWidth(), cs.GetHeight(), + ((cs.GetWidth() < cs.GetHeight()) ? cs.GetWidth() : cs.GetHeight()) / 2); + else + gc->DrawLines(5, points); /* draw solder paste ratio, if set */ if (pasteratio < -EPSILON && pasteratio > -0.5 && !OutlineMode) { wxPen pastepen(wxColour(160,160,80), 1, wxPENSTYLE_DOT); gc->SetPen(pastepen); wxBrush pastebrush(wxColour(160,160,80), wxBRUSHSTYLE_FDIAGONAL_HATCH); - gc->SetBrush(pastebrush); - /* avoid negative width/height for ellipses or obrounds */ - cs.Set(pastepoints[0].m_x, pastepoints[0].m_y, pastepoints[2].m_x - pastepoints[0].m_x, pastepoints[2].m_y - pastepoints[0].m_y); - if (padshape.CmpNoCase(wxT("C")) == 0) - gc->DrawEllipse(cs.GetX(), cs.GetY(), cs.GetWidth(), cs.GetHeight()); - else if (padshape.CmpNoCase(wxT("O")) == 0) - gc->DrawRoundedRectangle(cs.GetX(), cs.GetY(), cs.GetWidth(), cs.GetHeight(), - ((cs.GetWidth() < cs.GetHeight()) ? cs.GetWidth() : cs.GetHeight()) / 2); - else - gc->DrawLines(5, pastepoints); + gc->SetBrush(pastebrush); + /* avoid negative width/height for ellipses or obrounds */ + cs.Set(pastepoints[0].m_x, pastepoints[0].m_y, pastepoints[2].m_x - pastepoints[0].m_x, pastepoints[2].m_y - pastepoints[0].m_y); + if (padshape.CmpNoCase(wxT("C")) == 0) + gc->DrawEllipse(cs.GetX(), cs.GetY(), cs.GetWidth(), cs.GetHeight()); + else if (padshape.CmpNoCase(wxT("O")) == 0) + gc->DrawRoundedRectangle(cs.GetX(), cs.GetY(), cs.GetWidth(), cs.GetHeight(), + ((cs.GetWidth() < cs.GetHeight()) ? cs.GetWidth() : cs.GetHeight()) / 2); + else + gc->DrawLines(5, pastepoints); gc->SetPen(pen); gc->SetBrush(brush); } - /* optionally the hole in the pad */ - if (drillwidth > EPSILON) { - if (padshape.Cmp(wxT("circle")) == 0 && padwidth - drillwidth < 0.05) - gc->SetBrush(brushHole); - else - gc->SetBrush(*wxBLACK_BRUSH); - if (drillheight > EPSILON) { - if ((padrot > 45 && padrot < 135) || (padrot > 225 && padrot < 315)) { - double t = drillwidth; - drillwidth = drillheight; - drillheight = t; - } - cs.Set((padx + drillx - drillwidth/2) * Scale + midx, - (pady + drilly - drillheight/2) * Scale + midy, - drillwidth * Scale, drillheight * Scale); - gc->DrawRoundedRectangle(cs.GetX(), cs.GetY(), cs.GetWidth(), cs.GetHeight(), - ((cs.GetWidth() < cs.GetHeight()) ? cs.GetWidth() : cs.GetHeight()) / 2); - } else { - gc->DrawEllipse((padx + drillx - drillwidth/2) * Scale + midx, - (pady + drilly -drillwidth/2) * Scale + midy, - drillwidth * Scale, drillwidth * Scale); - } - } - /* draw the pin name inside the pad */ - if (ShowPinNumbers) { - wxDouble tw, th, td, tex; - gc->GetTextExtent(padpin, &tw, &th, &td, &tex); - gc->DrawText(padpin, padx * Scale + midx - tw/2, pady * Scale + midy - th/2); - } - continue; - } - if (!inpad) - continue; - wxString token = GetToken(&line); - if (token.CmpNoCase(wxT("Po")) == 0) { - padx = GetTokenDim(&line, unit_mm); /* this is relative to the footprint position, but in a footprint file, the position is always 0 */ - pady = GetTokenDim(&line, unit_mm); - } else if (token.CmpNoCase(wxT("Sh")) == 0) { - padpin = GetToken(&line); - padshape = GetToken(&line); - padwidth = GetTokenDim(&line, unit_mm); - padheight = GetTokenDim(&line, unit_mm); - paddeltax = GetTokenDim(&line, unit_mm); - paddeltay = GetTokenDim(&line, unit_mm); - padrot = NormalizeAngle(GetTokenLong(&line) / 10.0 - module_angle); - } else if (token.CmpNoCase(wxT("Dr")) == 0) { - drillwidth = GetTokenDim(&line, unit_mm); - drillx = GetTokenDim(&line, unit_mm); /* this is relative to the pad position */ - drilly = GetTokenDim(&line, unit_mm); - token = GetToken(&line); - if (token == wxT('O')) { - drillwidth = GetTokenDim(&line, unit_mm); - drillheight = GetTokenDim(&line, unit_mm); - } - } else if (token.CmpNoCase(wxT(".SolderPasteRatio")) == 0) { + /* optionally the hole in the pad */ + if (drillwidth > EPSILON) { + if (padshape.Cmp(wxT("circle")) == 0 && padwidth - drillwidth < 0.05) + gc->SetBrush(brushHole); + else + gc->SetBrush(*wxBLACK_BRUSH); + if (drillheight > EPSILON) { + if ((padrot > 45 && padrot < 135) || (padrot > 225 && padrot < 315)) { + double t = drillwidth; + drillwidth = drillheight; + drillheight = t; + } + cs.Set((padx + drillx - drillwidth/2) * Scale + midx, + (pady + drilly - drillheight/2) * Scale + midy, + drillwidth * Scale, drillheight * Scale); + gc->DrawRoundedRectangle(cs.GetX(), cs.GetY(), cs.GetWidth(), cs.GetHeight(), + ((cs.GetWidth() < cs.GetHeight()) ? cs.GetWidth() : cs.GetHeight()) / 2); + } else { + gc->DrawEllipse((padx + drillx - drillwidth/2) * Scale + midx, + (pady + drilly -drillwidth/2) * Scale + midy, + drillwidth * Scale, drillwidth * Scale); + } + } + /* draw the pin name inside the pad */ + if (ShowPinNumbers) { + wxDouble tw, th, td, tex; + gc->GetTextExtent(padpin, &tw, &th, &td, &tex); + gc->DrawText(padpin, padx * Scale + midx - tw/2, pady * Scale + midy - th/2); + } + continue; + } + if (!inpad) + continue; + wxString token = GetToken(&line); + if (token.CmpNoCase(wxT("Po")) == 0) { + padx = GetTokenDim(&line, unit_mm); /* this is relative to the footprint position, but in a footprint file, the position is always 0 */ + pady = GetTokenDim(&line, unit_mm); + } else if (token.CmpNoCase(wxT("Sh")) == 0) { + padpin = GetToken(&line); + padshape = GetToken(&line); + padwidth = GetTokenDim(&line, unit_mm); + padheight = GetTokenDim(&line, unit_mm); + paddeltax = GetTokenDim(&line, unit_mm); + paddeltay = GetTokenDim(&line, unit_mm); + padrot = NormalizeAngle(GetTokenLong(&line) / 10.0 - module_angle); + } else if (token.CmpNoCase(wxT("Dr")) == 0) { + drillwidth = GetTokenDim(&line, unit_mm); + drillx = GetTokenDim(&line, unit_mm); /* this is relative to the pad position */ + drilly = GetTokenDim(&line, unit_mm); + token = GetToken(&line); + if (token == wxT('O')) { + drillwidth = GetTokenDim(&line, unit_mm); + drillheight = GetTokenDim(&line, unit_mm); + } + } else if (token.CmpNoCase(wxT(".SolderPasteRatio")) == 0) { pasteratio = GetTokenDouble(&line); - } - } - - /* draw the measures */ - if (m_toolBar->GetToolToggled(IDT_MEASUREMENTS) && ShowMeasurements) { - pen.SetColour(0, 192, 192); - pen.SetWidth(1); - gc->SetPen(pen); - - font.SetPointSize(FontSizeLegend); - font.SetWeight(wxFONTWEIGHT_BOLD); - gc->SetFont(font, wxColour(0, 192, 192)); - - /* create a normalized pad size for the gap and extent, for the case that the primary - pad is rotated */ - CoordPair NormPad = Footprint[fp].PadSize[0]; - if (Footprint[fp].PadRightAngle[0]) - NormPad.Set(NormPad.GetY(), NormPad.GetX()); - - CoordPair padpins[2]; - if (Footprint[fp].Pitch > EPSILON) { - /* decide whether to also draw the pad extent (only when both spans are invalid) */ - bool drawextent = Equal(Footprint[fp].SpanHor, 0) && Equal(Footprint[fp].SpanVer, 0); - if (Footprint[fp].PitchVertical) { - /* decide whether to print the clearance between the pads */ - int pos = Equal(Footprint[fp].PitchPins[0].GetX(), Footprint[fp].PitchPins[1].GetX()) ? 1 : 0; - /* decide where to put the pitch dimension: left or right (prefer left) */ - int orientation = (Footprint[fp].PitchPins[0].GetX() > 0 && Footprint[fp].PitchPins[1].GetX() > 0) ? 270 : 90; - DrawDimension(gc, midx, midy, orientation, pos, Footprint[fp].Pitch, - Footprint[fp].PitchPins, bbox); - if (pos == 1) { - if (Footprint[fp].PitchPins[0].GetY() < Footprint[fp].PitchPins[1].GetY()) { - padpins[0].Set(Footprint[fp].PitchPins[0].GetX(), Footprint[fp].PitchPins[0].GetY() + NormPad.GetY() / 2); - padpins[1].Set(Footprint[fp].PitchPins[1].GetX(), Footprint[fp].PitchPins[1].GetY() - NormPad.GetY() / 2); - } else { - padpins[1].Set(Footprint[fp].PitchPins[0].GetX(), Footprint[fp].PitchPins[0].GetY() + NormPad.GetY() / 2); - padpins[0].Set(Footprint[fp].PitchPins[1].GetX(), Footprint[fp].PitchPins[1].GetY() - NormPad.GetY() / 2); - } - DrawDimension(gc, midx, midy, orientation, 0, - Footprint[fp].Pitch - NormPad.GetY(), - padpins, bbox); - } - if (drawextent && pos > 0) { - if (Footprint[fp].PitchPins[0].GetY() < Footprint[fp].PitchPins[1].GetY()) { - padpins[0].Set(Footprint[fp].PitchPins[0].GetX(), Footprint[fp].PitchPins[0].GetY() - NormPad.GetY() / 2); - padpins[1].Set(Footprint[fp].PitchPins[1].GetX(), Footprint[fp].PitchPins[1].GetY() + NormPad.GetY() / 2); - } else { - padpins[1].Set(Footprint[fp].PitchPins[0].GetX(), Footprint[fp].PitchPins[0].GetY() - NormPad.GetY() / 2); - padpins[0].Set(Footprint[fp].PitchPins[1].GetX(), Footprint[fp].PitchPins[1].GetY() + NormPad.GetY() / 2); - } - DrawDimension(gc, midx, midy, orientation, pos + 1, - Footprint[fp].Pitch + NormPad.GetY(), - padpins, bbox); - } - } else { - /* decide whether to print the clearance between the pads */ - int pos = Equal(Footprint[fp].PitchPins[0].GetY(), Footprint[fp].PitchPins[1].GetY()) ? 1 : 0; - /* decide where to put the pitch dimension: top or bottom (prefer top) */ - int orientation = (Footprint[fp].PitchPins[0].GetY() > 0 && Footprint[fp].PitchPins[1].GetY() > 0) ? 180 : 0; - DrawDimension(gc, midx, midy, orientation, pos, Footprint[fp].Pitch, - Footprint[fp].PitchPins, bbox); - if (pos == 1) { - if (Footprint[fp].PitchPins[0].GetX() < Footprint[fp].PitchPins[1].GetX()) { - padpins[0].Set(Footprint[fp].PitchPins[0].GetX() + NormPad.GetX() / 2, Footprint[fp].PitchPins[0].GetY()); - padpins[1].Set(Footprint[fp].PitchPins[1].GetX() - NormPad.GetX() / 2, Footprint[fp].PitchPins[1].GetY()); - } else { - padpins[1].Set(Footprint[fp].PitchPins[0].GetX() + NormPad.GetX() / 2, Footprint[fp].PitchPins[0].GetY()); - padpins[0].Set(Footprint[fp].PitchPins[1].GetX() - NormPad.GetX() / 2, Footprint[fp].PitchPins[1].GetY()); - } - DrawDimension(gc, midx, midy, orientation, 0, - Footprint[fp].Pitch - NormPad.GetX(), - padpins, bbox); - } - if (drawextent && pos > 0) { - if (Footprint[fp].PitchPins[0].GetX() < Footprint[fp].PitchPins[1].GetX()) { - padpins[0].Set(Footprint[fp].PitchPins[0].GetX() - NormPad.GetX() / 2, Footprint[fp].PitchPins[0].GetY()); - padpins[1].Set(Footprint[fp].PitchPins[1].GetX() + NormPad.GetX() / 2, Footprint[fp].PitchPins[1].GetY()); - } else { - padpins[1].Set(Footprint[fp].PitchPins[0].GetX() - NormPad.GetX() / 2, Footprint[fp].PitchPins[0].GetY()); - padpins[0].Set(Footprint[fp].PitchPins[1].GetX() + NormPad.GetX() / 2, Footprint[fp].PitchPins[1].GetY()); - } - DrawDimension(gc, midx, midy, orientation, pos + 1, - Footprint[fp].Pitch + NormPad.GetX(), - padpins, bbox); - } - } - } - /* check whether to print either span, or both */ - bool DrawVerSpan = true; - bool DrawHorSpan = true; - if (Equal(Footprint[fp].SpanHor, Footprint[fp].SpanVer)) { - /* both are equal, draw one of the two (at most) */ - if (Footprint[fp].PitchVertical) - DrawVerSpan = false; /* pitch is vertical, so draw span horizontal */ - else - DrawHorSpan = false; /* pitch is horizontal, so draw span vertical */ - } - if (DrawVerSpan && Footprint[fp].SpanVer > EPSILON) { - /* decide where to put the vertical span: left or right (prefer right) */ - int orientation = (Footprint[fp].SpanVerPins[0].GetX() < 0 && Footprint[fp].SpanVerPins[1].GetX() < 0) ? 90 : 270; - int stackpos = (Footprint[fp].SpanVer - NormPad.GetY() > 0.1) ? 1 : 0; - DrawDimension(gc, midx, midy, orientation, stackpos, Footprint[fp].SpanVer, - Footprint[fp].SpanVerPins, bbox); - /* draw the gap */ - if (stackpos > 0) { - if (Footprint[fp].SpanVerPins[0].GetY() < Footprint[fp].SpanVerPins[1].GetY()) { - padpins[0].Set(Footprint[fp].SpanVerPins[0].GetX(), Footprint[fp].SpanVerPins[0].GetY() + NormPad.GetY() / 2); - padpins[1].Set(Footprint[fp].SpanVerPins[1].GetX(), Footprint[fp].SpanVerPins[1].GetY() - NormPad.GetY() / 2); - } else { - padpins[1].Set(Footprint[fp].SpanVerPins[0].GetX(), Footprint[fp].SpanVerPins[0].GetY() + NormPad.GetY() / 2); - padpins[0].Set(Footprint[fp].SpanVerPins[1].GetX(), Footprint[fp].SpanVerPins[1].GetY() - NormPad.GetY() / 2); - } - DrawDimension(gc, midx, midy, orientation, 0, - Footprint[fp].SpanVer - NormPad.GetY(), - padpins, bbox); - } - /* draw the extent */ - if (Footprint[fp].SpanVerPins[0].GetY() < Footprint[fp].SpanVerPins[1].GetY()) { - padpins[0].Set(Footprint[fp].SpanVerPins[0].GetX(), Footprint[fp].SpanVerPins[0].GetY() - NormPad.GetY() / 2); - padpins[1].Set(Footprint[fp].SpanVerPins[1].GetX(), Footprint[fp].SpanVerPins[1].GetY() + NormPad.GetY() / 2); - } else { - padpins[1].Set(Footprint[fp].SpanVerPins[0].GetX(), Footprint[fp].SpanVerPins[0].GetY() - NormPad.GetY() / 2); - padpins[0].Set(Footprint[fp].SpanVerPins[1].GetX(), Footprint[fp].SpanVerPins[1].GetY() + NormPad.GetY() / 2); - } - DrawDimension(gc, midx, midy, orientation, stackpos + 1, - Footprint[fp].SpanVer + NormPad.GetY(), - padpins, bbox); - } - if (DrawHorSpan && Footprint[fp].SpanHor > EPSILON) { - /* decide where to put the horizontal span: top or bottom (prefer bottom) */ - int orientation = (Footprint[fp].SpanHorPins[0].GetY() < 0 && Footprint[fp].SpanHorPins[1].GetY() < 0) ? 0 : 180; - int stackpos = (Footprint[fp].SpanHor - NormPad.GetX() > 0.1) ? 1 : 0; - DrawDimension(gc, midx, midy, orientation, stackpos, Footprint[fp].SpanHor, - Footprint[fp].SpanHorPins, bbox); - /* draw the gap */ - if (stackpos > 0) { - if (Footprint[fp].SpanHorPins[0].GetX() < Footprint[fp].SpanHorPins[1].GetX()) { - padpins[0].Set(Footprint[fp].SpanHorPins[0].GetX() + NormPad.GetX() / 2, Footprint[fp].SpanHorPins[0].GetY()); - padpins[1].Set(Footprint[fp].SpanHorPins[1].GetX() - NormPad.GetX() / 2, Footprint[fp].SpanHorPins[1].GetY()); - } else { - padpins[1].Set(Footprint[fp].SpanHorPins[0].GetX() + NormPad.GetX() / 2, Footprint[fp].SpanHorPins[0].GetY()); - padpins[0].Set(Footprint[fp].SpanHorPins[1].GetX() - NormPad.GetX() / 2, Footprint[fp].SpanHorPins[1].GetY()); - } - DrawDimension(gc, midx, midy, orientation, 0, - Footprint[fp].SpanHor - NormPad.GetX(), - padpins, bbox); - } - /* draw the extent */ - if (Footprint[fp].SpanHorPins[0].GetX() < Footprint[fp].SpanHorPins[1].GetX()) { - padpins[0].Set(Footprint[fp].SpanHorPins[0].GetX() - NormPad.GetX() / 2, Footprint[fp].SpanHorPins[0].GetY()); - padpins[1].Set(Footprint[fp].SpanHorPins[1].GetX() + NormPad.GetX() / 2, Footprint[fp].SpanHorPins[1].GetY()); - } else { - padpins[1].Set(Footprint[fp].SpanHorPins[0].GetX() - NormPad.GetX() / 2, Footprint[fp].SpanHorPins[0].GetY()); - padpins[0].Set(Footprint[fp].SpanHorPins[1].GetX() + NormPad.GetX() / 2, Footprint[fp].SpanHorPins[1].GetY()); - } - DrawDimension(gc, midx, midy, orientation, stackpos + 1, - Footprint[fp].SpanHor + NormPad.GetX(), - padpins, bbox); - } - - } /* if (draw measures) */ - } /* for (fp) */ - - /* draw cross for the centre point */ - if (DrawCentreCross) { - pen.SetColour(192, 192, 192); - pen.SetWidth(1); - gc->SetPen(pen); - #define CROSS_SIZE 12 - points[0].m_x = midx - CROSS_SIZE; - points[0].m_y = midy; - points[1].m_x = midx + CROSS_SIZE; - points[1].m_y = midy; - gc->DrawLines(2, points); - points[0].m_x = midx; - points[0].m_y = midy - CROSS_SIZE; - points[1].m_x = midx; - points[1].m_y = midy + CROSS_SIZE; - gc->DrawLines(2, points); - } + } + } + + /* draw the measures */ + if (m_toolBar->GetToolToggled(IDT_MEASUREMENTS) && ShowMeasurements) { + pen.SetColour(0, 192, 192); + pen.SetWidth(1); + gc->SetPen(pen); + + font.SetPointSize(FontSizeLegend); + font.SetWeight(wxFONTWEIGHT_BOLD); + gc->SetFont(font, wxColour(0, 192, 192)); + + /* create a normalized pad size for the gap and extent, for the case that the primary + pad is rotated */ + CoordPair NormPad = Footprint[fp].PadSize[0]; + if (Footprint[fp].PadRightAngle[0]) + NormPad.Set(NormPad.GetY(), NormPad.GetX()); + + CoordPair padpins[2]; + if (Footprint[fp].Pitch > EPSILON) { + /* decide whether to also draw the pad extent (only when both spans are invalid) */ + bool drawextent = Equal(Footprint[fp].SpanHor, 0) && Equal(Footprint[fp].SpanVer, 0); + if (Footprint[fp].PitchVertical) { + /* decide whether to print the clearance between the pads */ + int pos = Equal(Footprint[fp].PitchPins[0].GetX(), Footprint[fp].PitchPins[1].GetX()) ? 1 : 0; + /* decide where to put the pitch dimension: left or right (prefer left) */ + int orientation = (Footprint[fp].PitchPins[0].GetX() > 0 && Footprint[fp].PitchPins[1].GetX() > 0) ? 270 : 90; + DrawDimension(gc, midx, midy, orientation, pos, Footprint[fp].Pitch, + Footprint[fp].PitchPins, bbox); + if (pos == 1) { + if (Footprint[fp].PitchPins[0].GetY() < Footprint[fp].PitchPins[1].GetY()) { + padpins[0].Set(Footprint[fp].PitchPins[0].GetX(), Footprint[fp].PitchPins[0].GetY() + NormPad.GetY() / 2); + padpins[1].Set(Footprint[fp].PitchPins[1].GetX(), Footprint[fp].PitchPins[1].GetY() - NormPad.GetY() / 2); + } else { + padpins[1].Set(Footprint[fp].PitchPins[0].GetX(), Footprint[fp].PitchPins[0].GetY() + NormPad.GetY() / 2); + padpins[0].Set(Footprint[fp].PitchPins[1].GetX(), Footprint[fp].PitchPins[1].GetY() - NormPad.GetY() / 2); + } + DrawDimension(gc, midx, midy, orientation, 0, + Footprint[fp].Pitch - NormPad.GetY(), + padpins, bbox); + } + if (drawextent && pos > 0) { + if (Footprint[fp].PitchPins[0].GetY() < Footprint[fp].PitchPins[1].GetY()) { + padpins[0].Set(Footprint[fp].PitchPins[0].GetX(), Footprint[fp].PitchPins[0].GetY() - NormPad.GetY() / 2); + padpins[1].Set(Footprint[fp].PitchPins[1].GetX(), Footprint[fp].PitchPins[1].GetY() + NormPad.GetY() / 2); + } else { + padpins[1].Set(Footprint[fp].PitchPins[0].GetX(), Footprint[fp].PitchPins[0].GetY() - NormPad.GetY() / 2); + padpins[0].Set(Footprint[fp].PitchPins[1].GetX(), Footprint[fp].PitchPins[1].GetY() + NormPad.GetY() / 2); + } + DrawDimension(gc, midx, midy, orientation, pos + 1, + Footprint[fp].Pitch + NormPad.GetY(), + padpins, bbox); + } + } else { + /* decide whether to print the clearance between the pads */ + int pos = Equal(Footprint[fp].PitchPins[0].GetY(), Footprint[fp].PitchPins[1].GetY()) ? 1 : 0; + /* decide where to put the pitch dimension: top or bottom (prefer top) */ + int orientation = (Footprint[fp].PitchPins[0].GetY() > 0 && Footprint[fp].PitchPins[1].GetY() > 0) ? 180 : 0; + DrawDimension(gc, midx, midy, orientation, pos, Footprint[fp].Pitch, + Footprint[fp].PitchPins, bbox); + if (pos == 1) { + if (Footprint[fp].PitchPins[0].GetX() < Footprint[fp].PitchPins[1].GetX()) { + padpins[0].Set(Footprint[fp].PitchPins[0].GetX() + NormPad.GetX() / 2, Footprint[fp].PitchPins[0].GetY()); + padpins[1].Set(Footprint[fp].PitchPins[1].GetX() - NormPad.GetX() / 2, Footprint[fp].PitchPins[1].GetY()); + } else { + padpins[1].Set(Footprint[fp].PitchPins[0].GetX() + NormPad.GetX() / 2, Footprint[fp].PitchPins[0].GetY()); + padpins[0].Set(Footprint[fp].PitchPins[1].GetX() - NormPad.GetX() / 2, Footprint[fp].PitchPins[1].GetY()); + } + DrawDimension(gc, midx, midy, orientation, 0, + Footprint[fp].Pitch - NormPad.GetX(), + padpins, bbox); + } + if (drawextent && pos > 0) { + if (Footprint[fp].PitchPins[0].GetX() < Footprint[fp].PitchPins[1].GetX()) { + padpins[0].Set(Footprint[fp].PitchPins[0].GetX() - NormPad.GetX() / 2, Footprint[fp].PitchPins[0].GetY()); + padpins[1].Set(Footprint[fp].PitchPins[1].GetX() + NormPad.GetX() / 2, Footprint[fp].PitchPins[1].GetY()); + } else { + padpins[1].Set(Footprint[fp].PitchPins[0].GetX() - NormPad.GetX() / 2, Footprint[fp].PitchPins[0].GetY()); + padpins[0].Set(Footprint[fp].PitchPins[1].GetX() + NormPad.GetX() / 2, Footprint[fp].PitchPins[1].GetY()); + } + DrawDimension(gc, midx, midy, orientation, pos + 1, + Footprint[fp].Pitch + NormPad.GetX(), + padpins, bbox); + } + } + } + /* check whether to print either span, or both */ + bool DrawVerSpan = true; + bool DrawHorSpan = true; + if (Equal(Footprint[fp].SpanHor, Footprint[fp].SpanVer)) { + /* both are equal, draw one of the two (at most) */ + if (Footprint[fp].PitchVertical) + DrawVerSpan = false; /* pitch is vertical, so draw span horizontal */ + else + DrawHorSpan = false; /* pitch is horizontal, so draw span vertical */ + } + if (DrawVerSpan && Footprint[fp].SpanVer > EPSILON) { + /* decide where to put the vertical span: left or right (prefer right) */ + int orientation = (Footprint[fp].SpanVerPins[0].GetX() < 0 && Footprint[fp].SpanVerPins[1].GetX() < 0) ? 90 : 270; + int stackpos = (Footprint[fp].SpanVer - NormPad.GetY() > 0.1) ? 1 : 0; + DrawDimension(gc, midx, midy, orientation, stackpos, Footprint[fp].SpanVer, + Footprint[fp].SpanVerPins, bbox); + /* draw the gap */ + if (stackpos > 0) { + if (Footprint[fp].SpanVerPins[0].GetY() < Footprint[fp].SpanVerPins[1].GetY()) { + padpins[0].Set(Footprint[fp].SpanVerPins[0].GetX(), Footprint[fp].SpanVerPins[0].GetY() + NormPad.GetY() / 2); + padpins[1].Set(Footprint[fp].SpanVerPins[1].GetX(), Footprint[fp].SpanVerPins[1].GetY() - NormPad.GetY() / 2); + } else { + padpins[1].Set(Footprint[fp].SpanVerPins[0].GetX(), Footprint[fp].SpanVerPins[0].GetY() + NormPad.GetY() / 2); + padpins[0].Set(Footprint[fp].SpanVerPins[1].GetX(), Footprint[fp].SpanVerPins[1].GetY() - NormPad.GetY() / 2); + } + DrawDimension(gc, midx, midy, orientation, 0, + Footprint[fp].SpanVer - NormPad.GetY(), + padpins, bbox); + } + /* draw the extent */ + if (Footprint[fp].SpanVerPins[0].GetY() < Footprint[fp].SpanVerPins[1].GetY()) { + padpins[0].Set(Footprint[fp].SpanVerPins[0].GetX(), Footprint[fp].SpanVerPins[0].GetY() - NormPad.GetY() / 2); + padpins[1].Set(Footprint[fp].SpanVerPins[1].GetX(), Footprint[fp].SpanVerPins[1].GetY() + NormPad.GetY() / 2); + } else { + padpins[1].Set(Footprint[fp].SpanVerPins[0].GetX(), Footprint[fp].SpanVerPins[0].GetY() - NormPad.GetY() / 2); + padpins[0].Set(Footprint[fp].SpanVerPins[1].GetX(), Footprint[fp].SpanVerPins[1].GetY() + NormPad.GetY() / 2); + } + DrawDimension(gc, midx, midy, orientation, stackpos + 1, + Footprint[fp].SpanVer + NormPad.GetY(), + padpins, bbox); + } + if (DrawHorSpan && Footprint[fp].SpanHor > EPSILON) { + /* decide where to put the horizontal span: top or bottom (prefer bottom) */ + int orientation = (Footprint[fp].SpanHorPins[0].GetY() < 0 && Footprint[fp].SpanHorPins[1].GetY() < 0) ? 0 : 180; + int stackpos = (Footprint[fp].SpanHor - NormPad.GetX() > 0.1) ? 1 : 0; + DrawDimension(gc, midx, midy, orientation, stackpos, Footprint[fp].SpanHor, + Footprint[fp].SpanHorPins, bbox); + /* draw the gap */ + if (stackpos > 0) { + if (Footprint[fp].SpanHorPins[0].GetX() < Footprint[fp].SpanHorPins[1].GetX()) { + padpins[0].Set(Footprint[fp].SpanHorPins[0].GetX() + NormPad.GetX() / 2, Footprint[fp].SpanHorPins[0].GetY()); + padpins[1].Set(Footprint[fp].SpanHorPins[1].GetX() - NormPad.GetX() / 2, Footprint[fp].SpanHorPins[1].GetY()); + } else { + padpins[1].Set(Footprint[fp].SpanHorPins[0].GetX() + NormPad.GetX() / 2, Footprint[fp].SpanHorPins[0].GetY()); + padpins[0].Set(Footprint[fp].SpanHorPins[1].GetX() - NormPad.GetX() / 2, Footprint[fp].SpanHorPins[1].GetY()); + } + DrawDimension(gc, midx, midy, orientation, 0, + Footprint[fp].SpanHor - NormPad.GetX(), + padpins, bbox); + } + /* draw the extent */ + if (Footprint[fp].SpanHorPins[0].GetX() < Footprint[fp].SpanHorPins[1].GetX()) { + padpins[0].Set(Footprint[fp].SpanHorPins[0].GetX() - NormPad.GetX() / 2, Footprint[fp].SpanHorPins[0].GetY()); + padpins[1].Set(Footprint[fp].SpanHorPins[1].GetX() + NormPad.GetX() / 2, Footprint[fp].SpanHorPins[1].GetY()); + } else { + padpins[1].Set(Footprint[fp].SpanHorPins[0].GetX() - NormPad.GetX() / 2, Footprint[fp].SpanHorPins[0].GetY()); + padpins[0].Set(Footprint[fp].SpanHorPins[1].GetX() + NormPad.GetX() / 2, Footprint[fp].SpanHorPins[1].GetY()); + } + DrawDimension(gc, midx, midy, orientation, stackpos + 1, + Footprint[fp].SpanHor + NormPad.GetX(), + padpins, bbox); + } + + } /* if (draw measures) */ + } /* for (fp) */ + + /* draw cross for the centre point */ + if (DrawCentreCross) { + pen.SetColour(192, 192, 192); + pen.SetWidth(1); + gc->SetPen(pen); + #define CROSS_SIZE 12 + points[0].m_x = midx - CROSS_SIZE; + points[0].m_y = midy; + points[1].m_x = midx + CROSS_SIZE; + points[1].m_y = midy; + gc->DrawLines(2, points); + points[0].m_x = midx; + points[0].m_y = midy - CROSS_SIZE; + points[1].m_x = midx; + points[1].m_y = midy + CROSS_SIZE; + gc->DrawLines(2, points); + } #if 0 //??? only for testing bounding box - pen.SetColour(192, 0, 192); - pen.SetWidth(1); - gc->SetPen(pen); - gc->SetBrush(*wxTRANSPARENT_BRUSH); - gc->DrawRectangle(bbox.GetX() * Scale + midx, bbox.GetY() * Scale + midy, - bbox.GetWidth() * Scale, bbox.GetHeight() * Scale); + pen.SetColour(192, 0, 192); + pen.SetWidth(1); + gc->SetPen(pen); + gc->SetBrush(*wxTRANSPARENT_BRUSH); + gc->DrawRectangle(bbox.GetX() * Scale + midx, bbox.GetY() * Scale + midy, + bbox.GetWidth() * Scale, bbox.GetHeight() * Scale); #endif } void libmngrFrame::ResizeModelViewport() { #if !defined NO_3DMODEL - wxASSERT(glCanvas && glContext); + wxASSERT(glCanvas && glContext); - wxSize sz = m_panelView->GetSize(); - glViewport(0, 0, sz.x, sz.y); + wxSize sz = m_panelView->GetSize(); + glViewport(0, 0, sz.x, sz.y); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); CyberX3D::ViewpointNode *view = sceneGraph.getViewpointNode(); if (view == NULL) @@ -3677,24 +3678,24 @@ void libmngrFrame::ResizeModelViewport() const double zFar = 10000.0; const double pi = 3.1415926535897932384626433832795; - /* Calculate the distance from 0 of the y clipping plane. Basically trig to calculate position - of clipper at zNear. - Note: tan( double ) uses radians but OpenGL works in degrees so we convert degrees to radians - by dividing by 360 then multiplying by pi. - Formula below corrected by Carsten Jurenz: - fH = tan( (fov / 2) / 180 * pi ) * zNear; - Which can be reduced to: - fH = tan( fov / 360 * pi ) * zNear; - */ - double fH = tan( fov / 360 * pi ) * zNear; - /* Calculate the distance from 0 of the x clipping plane based on the aspect ratio. */ - double fW = fH * aspect; - /* Finally call glFrustum, this is all gluPerspective does anyway! This is why we calculate - half the distance between the clipping planes - glFrustum takes an offset from zero for - each clipping planes distance. (Saves 2 divides) */ - glFrustum(-fW, fW, -fH, fH, zNear, zFar); - - glMatrixMode(GL_MODELVIEW); + /* Calculate the distance from 0 of the y clipping plane. Basically trig to calculate position + of clipper at zNear. + Note: tan( double ) uses radians but OpenGL works in degrees so we convert degrees to radians + by dividing by 360 then multiplying by pi. + Formula below corrected by Carsten Jurenz: + fH = tan( (fov / 2) / 180 * pi ) * zNear; + Which can be reduced to: + fH = tan( fov / 360 * pi ) * zNear; + */ + double fH = tan( fov / 360 * pi ) * zNear; + /* Calculate the distance from 0 of the x clipping plane based on the aspect ratio. */ + double fW = fH * aspect; + /* Finally call glFrustum, this is all gluPerspective does anyway! This is why we calculate + half the distance between the clipping planes - glFrustum takes an offset from zero for + each clipping planes distance. (Saves 2 divides) */ + glFrustum(-fW, fW, -fH, fH, zNear, zFar); + + glMatrixMode(GL_MODELVIEW); #endif } @@ -3702,345 +3703,345 @@ void libmngrFrame::DrawModels(float xangle, float yangle) { #if !defined NO_3DMODEL if (glCanvas == NULL) { - int attribList[] = { WX_GL_RGBA, + int attribList[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, #if defined _WIN32 WX_GL_SAMPLE_BUFFERS, GL_TRUE, // Multi-sampling (apparently not currently supported on Linux) #endif WX_GL_DEPTH_SIZE, 16, 0, 0 }; - wxSize sz = m_panelView->GetSize(); - glCanvas = new wxGLCanvas(m_panelView, wxID_ANY, attribList, m_panelView->GetPosition(), m_panelView->GetSize(), - m_panelView->GetWindowStyleFlag() | wxTRANSPARENT_WINDOW, wxT("PartCanvas")); - #if defined _WIN32 - wxBoxSizer *pSizer = dynamic_cast(m_panelView->GetSizer()); + wxSize sz = m_panelView->GetSize(); + glCanvas = new wxGLCanvas(m_panelView, wxID_ANY, attribList, m_panelView->GetPosition(), m_panelView->GetSize(), + m_panelView->GetWindowStyleFlag() | wxTRANSPARENT_WINDOW, wxT("PartCanvas")); + #if defined _WIN32 + wxBoxSizer *pSizer = dynamic_cast(m_panelView->GetSizer()); if (!pSizer) { pSizer = new wxBoxSizer(wxVERTICAL); - m_panelView->SetSizer(pSizer); + m_panelView->SetSizer(pSizer); } - pSizer->Add(glCanvas, 1, wxGROW|wxALL, 0); + pSizer->Add(glCanvas, 1, wxGROW|wxALL, 0); #else - /* for unknown reasons, without a re-parent, the mouse interaction - on glCanvas (on a panel) will not work on GTK */ //??? check whether this still is the case - glCanvas->Reparent(m_panelView->GetParent()); - glCanvas->SetSize(sz); - // For the model to appear, slightly enlarge the main window, or hide and then re-show the side panel with the parameters. - #endif - glCanvas->Show(); - glCanvas->Refresh(true); - - glCanvas->Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(libmngrFrame::OnViewCentre), NULL, this); - glCanvas->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(libmngrFrame::OnViewStartDrag), NULL, this); - glCanvas->Connect(wxEVT_MOTION, wxMouseEventHandler(libmngrFrame::OnViewDrag), NULL, this); - } - if (glContext == NULL) { - glContext = new wxGLContext(glCanvas); - glContext->SetCurrent(*glCanvas); - ResizeModelViewport(); - } + /* for unknown reasons, without a re-parent, the mouse interaction + on glCanvas (on a panel) will not work on GTK */ //??? check whether this still is the case + glCanvas->Reparent(m_panelView->GetParent()); + glCanvas->SetSize(sz); + // For the model to appear, slightly enlarge the main window, or hide and then re-show the side panel with the parameters. + #endif + glCanvas->Show(); + glCanvas->Refresh(true); + + glCanvas->Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(libmngrFrame::OnViewCentre), NULL, this); + glCanvas->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(libmngrFrame::OnViewStartDrag), NULL, this); + glCanvas->Connect(wxEVT_MOTION, wxMouseEventHandler(libmngrFrame::OnViewDrag), NULL, this); + } + if (glContext == NULL) { + glContext = new wxGLContext(glCanvas); + glContext->SetCurrent(*glCanvas); + ResizeModelViewport(); + } SetSceneGraphBackground(clr3DModelMode.GetRGB()); DrawSceneGraph(&sceneGraph, OGL_RENDERING_TEXTURE, xangle - 30.0, yangle); - glCanvas->SwapBuffers(); + glCanvas->SwapBuffers(); #endif } void libmngrFrame::DrawDimension(wxGraphicsContext *gc, int midx, int midy, - int orientation, int stack, double value, - const CoordPair pins[2], const CoordSize& bbox) -{ - wxASSERT(orientation == 0 || orientation == 90 || orientation == 180 || orientation == 270); - bool horz = (orientation == 90 || orientation == 270); - int sign = (orientation == 180 || orientation == 270) ? 1 : -1; - - /* calculate the text size first (needed for the offset for stacking dimensions) */ - wxString text = wxString::Format(wxT("%.2f (%.1f)"), value, value / 0.0254); - wxDouble tw, th, td, tex; - gc->GetTextExtent(text, &tw, &th, &td, &tex); - - - wxPoint2DDouble points[2]; - if (horz) { - double pos = (sign > 0) ? bbox.GetRight() : bbox.GetLeft(); - double xt = pos * Scale + midx + sign * (DimensionOffset + stack * th * MEASURE_GAP); - for (int idx = 0; idx < 2; idx++) { - points[0].m_x = pins[idx].GetX() * Scale + midx + sign * LINE_OFFSET; - points[1].m_x = xt + sign * LINE_OFFSET; - points[0].m_y = points[1].m_y = pins[idx].GetY() * Scale + midy; - gc->DrawLines(2, points); - } - - points[0].m_x = points[1].m_x = xt; - points[0].m_y = pins[0].GetY() * Scale + midy; - points[1].m_y = pins[1].GetY() * Scale + midy; - gc->DrawLines(2, points); - - double yt = (pins[0].GetY() + pins[1].GetY()) / 2 * Scale + midy; - gc->DrawText(text, (sign > 0) ? xt + LINE_OFFSET : xt - th - LINE_OFFSET, yt + tw/2, M_PI / 2); - } else { - double pos = (sign > 0) ? bbox.GetBottom() : bbox.GetTop(); - double yt = pos * Scale + midy + sign * (DimensionOffset + stack * th * MEASURE_GAP); - for (int idx = 0; idx < 2; idx++) { - points[0].m_x = points[1].m_x = pins[idx].GetX() * Scale + midx; - points[0].m_y = pins[idx].GetY() * Scale + midy + sign * LINE_OFFSET; - points[1].m_y = yt + sign * LINE_OFFSET; - gc->DrawLines(2, points); - } - - points[0].m_x = pins[0].GetX() * Scale + midx; - points[1].m_x = pins[1].GetX() * Scale + midx; - points[0].m_y = points[1].m_y = yt; - gc->DrawLines(2, points); - - double xt = (pins[0].GetX() + pins[1].GetX()) / 2 * Scale + midx; - gc->DrawText(text, xt - tw/2, (sign > 0) ? yt + LINE_OFFSET : yt - th - LINE_OFFSET); - } + int orientation, int stack, double value, + const CoordPair pins[2], const CoordSize& bbox) +{ + wxASSERT(orientation == 0 || orientation == 90 || orientation == 180 || orientation == 270); + bool horz = (orientation == 90 || orientation == 270); + int sign = (orientation == 180 || orientation == 270) ? 1 : -1; + + /* calculate the text size first (needed for the offset for stacking dimensions) */ + wxString text = wxString::Format(wxT("%.2f (%.1f)"), value, value / 0.0254); + wxDouble tw, th, td, tex; + gc->GetTextExtent(text, &tw, &th, &td, &tex); + + + wxPoint2DDouble points[2]; + if (horz) { + double pos = (sign > 0) ? bbox.GetRight() : bbox.GetLeft(); + double xt = pos * Scale + midx + sign * (DimensionOffset + stack * th * MEASURE_GAP); + for (int idx = 0; idx < 2; idx++) { + points[0].m_x = pins[idx].GetX() * Scale + midx + sign * LINE_OFFSET; + points[1].m_x = xt + sign * LINE_OFFSET; + points[0].m_y = points[1].m_y = pins[idx].GetY() * Scale + midy; + gc->DrawLines(2, points); + } + + points[0].m_x = points[1].m_x = xt; + points[0].m_y = pins[0].GetY() * Scale + midy; + points[1].m_y = pins[1].GetY() * Scale + midy; + gc->DrawLines(2, points); + + double yt = (pins[0].GetY() + pins[1].GetY()) / 2 * Scale + midy; + gc->DrawText(text, (sign > 0) ? xt + LINE_OFFSET : xt - th - LINE_OFFSET, yt + tw/2, M_PI / 2); + } else { + double pos = (sign > 0) ? bbox.GetBottom() : bbox.GetTop(); + double yt = pos * Scale + midy + sign * (DimensionOffset + stack * th * MEASURE_GAP); + for (int idx = 0; idx < 2; idx++) { + points[0].m_x = points[1].m_x = pins[idx].GetX() * Scale + midx; + points[0].m_y = pins[idx].GetY() * Scale + midy + sign * LINE_OFFSET; + points[1].m_y = yt + sign * LINE_OFFSET; + gc->DrawLines(2, points); + } + + points[0].m_x = pins[0].GetX() * Scale + midx; + points[1].m_x = pins[1].GetX() * Scale + midx; + points[0].m_y = points[1].m_y = yt; + gc->DrawLines(2, points); + + double xt = (pins[0].GetX() + pins[1].GetX()) / 2 * Scale + midx; + gc->DrawText(text, xt - tw/2, (sign > 0) ? yt + LINE_OFFSET : yt - th - LINE_OFFSET); + } } void libmngrFrame::OnPaintViewport(wxPaintEvent& /*event*/) { - wxPaintDC dc(m_panelView); - wxGraphicsContext *gc = wxGraphicsContext::Create(dc); - if (PartData[0].Count() == 0 && PartData[1].Count() == 0) { - wxColour clrText = wxColour(128, 128, 128); - wxFont font(24, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD); - font.SetPointSize(24); - gc->SetFont(font, clrText); - wxString text = SymbolMode ? wxT("NO SYMBOL TO DISPLAY") : (ModelMode ? wxT("NO MODEL TO DISPLAY") : wxT("NO FOOTPRINT TO DISPLAY")); - wxSize sz = m_panelView->GetClientSize(); - wxDouble tw, th, td, tex; - gc->GetTextExtent(text, &tw, &th, &td, &tex); - gc->DrawText(text, sz.GetWidth() / 2 + OffsetX - tw/2, sz.GetHeight() / 2 + OffsetY - th/2); - return; - } - - int transp[2] = { wxALPHA_OPAQUE, 0x80 }; /* this is the transparency for the overlay */ - if (!CompareMode || !m_toolBar->GetToolToggled(IDT_LEFTFOOTPRINT)) - transp[1] = wxALPHA_OPAQUE; - - wxSize sz = m_panelView->GetClientSize(); - long midx = sz.GetWidth() / 2 + OffsetX; - long midy = sz.GetHeight() / 2 + OffsetY; - - if (SymbolMode) - DrawSymbols(gc, midx, midy, transp); - else if (ModelMode) - DrawModels(OffsetY / 5.0, OffsetX / 5.0); - else - DrawFootprints(gc, midx, midy, transp); + wxPaintDC dc(m_panelView); + wxGraphicsContext *gc = wxGraphicsContext::Create(dc); + if (PartData[0].Count() == 0 && PartData[1].Count() == 0) { + wxColour clrText = wxColour(128, 128, 128); + wxFont font(24, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD); + font.SetPointSize(24); + gc->SetFont(font, clrText); + wxString text = SymbolMode ? wxT("NO SYMBOL TO DISPLAY") : (ModelMode ? wxT("NO MODEL TO DISPLAY") : wxT("NO FOOTPRINT TO DISPLAY")); + wxSize sz = m_panelView->GetClientSize(); + wxDouble tw, th, td, tex; + gc->GetTextExtent(text, &tw, &th, &td, &tex); + gc->DrawText(text, sz.GetWidth() / 2 + OffsetX - tw/2, sz.GetHeight() / 2 + OffsetY - th/2); + return; + } + + int transp[2] = { wxALPHA_OPAQUE, 0x80 }; /* this is the transparency for the overlay */ + if (!CompareMode || !m_toolBar->GetToolToggled(IDT_LEFTFOOTPRINT)) + transp[1] = wxALPHA_OPAQUE; + + wxSize sz = m_panelView->GetClientSize(); + long midx = sz.GetWidth() / 2 + OffsetX; + long midy = sz.GetHeight() / 2 + OffsetY; + + if (SymbolMode) + DrawSymbols(gc, midx, midy, transp); + else if (ModelMode) + DrawModels(OffsetY / 5.0, OffsetX / 5.0); + else + DrawFootprints(gc, midx, midy, transp); } void libmngrFrame::OnSizeViewport(wxSizeEvent& /*event*/) { - if (ModelMode) { + if (ModelMode) { #if !defined NO_3DMODEL wxASSERT(glCanvas && glContext); #endif - ResizeModelViewport(); - } - m_panelView->Refresh(); - /* move the filter edit field (if it exists already) */ - if (m_statusBar->GetFieldsCount() > 1) { - wxRect rect; - m_statusBar->GetFieldRect(1, rect); - m_editFilter->SetSize(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight(), 0); - } + ResizeModelViewport(); + } + m_panelView->Refresh(); + /* move the filter edit field (if it exists already) */ + if (m_statusBar->GetFieldsCount() > 1) { + wxRect rect; + m_statusBar->GetFieldRect(1, rect); + m_editFilter->SetSize(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight(), 0); + } } void libmngrFrame::OnZoomIn(wxCommandEvent& /*event*/) { - if (Scale < SCALE_MAX) { - Scale *= 1.1892; + if (Scale < SCALE_MAX) { + Scale *= 1.1892; if (ModelMode) ResizeModelViewport(); - m_panelView->Refresh(); - } else { - Scale = SCALE_MAX; - } + m_panelView->Refresh(); + } else { + Scale = SCALE_MAX; + } } void libmngrFrame::OnZoomOut(wxCommandEvent& /*event*/) { - if (Scale > SCALE_MIN) { - Scale /= 1.1892; + if (Scale > SCALE_MIN) { + Scale /= 1.1892; if (ModelMode) ResizeModelViewport(); - m_panelView->Refresh(); - } else { - Scale = SCALE_MIN; - } + m_panelView->Refresh(); + } else { + Scale = SCALE_MIN; + } } void libmngrFrame::On3DView(wxCommandEvent& /*event*/) { #if !defined NO_3DMODEL - /* not active in symbol mode */ - if (SymbolMode) { - wxMessageBox(wxT("3D view is only relevant in footprint mode.")); - m_toolBar->ToggleTool(IDT_3DVIEW, false); - return; - } - - /* turn off compare mode (if needed) */ - if (CompareMode) { - CompareMode = false; - m_toolBar->EnableTool(IDT_LEFTFOOTPRINT, CompareMode); - m_toolBar->EnableTool(IDT_RIGHTFOOTPRINT, CompareMode); - m_toolBar->ToggleTool(IDT_LEFTFOOTPRINT, CompareMode); - m_toolBar->ToggleTool(IDT_RIGHTFOOTPRINT, CompareMode); + /* not active in symbol mode */ + if (SymbolMode) { + wxMessageBox(wxT("3D view is only relevant in footprint mode.")); + m_toolBar->ToggleTool(IDT_3DVIEW, false); + return; + } + + /* turn off compare mode (if needed) */ + if (CompareMode) { + CompareMode = false; + m_toolBar->EnableTool(IDT_LEFTFOOTPRINT, CompareMode); + m_toolBar->EnableTool(IDT_RIGHTFOOTPRINT, CompareMode); + m_toolBar->ToggleTool(IDT_LEFTFOOTPRINT, CompareMode); + m_toolBar->ToggleTool(IDT_RIGHTFOOTPRINT, CompareMode); m_toolBar->Refresh(); - m_radioViewLeft->Enable(CompareMode); - m_radioViewRight->Enable(CompareMode); - m_radioViewLeft->SetValue(true); - /* remove the selection in the right listctrl (we only keep the left footprint) */ - RemoveSelection(m_listModulesRight, &SelectedPartRight); - PartData[1].Clear(); - /* check whether there is a selection in the left listctrl, only enable - the buttons if so */ - long idx = m_listModulesRight->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - if (idx >= 0) - EnableButtons(LEFTPANEL); - m_radioViewLeft->SetValue(true); - m_radioViewRight->SetValue(false); - } - - ModelMode = m_toolBar->GetToolToggled(IDT_3DVIEW); - if (ModelMode) { + m_radioViewLeft->Enable(CompareMode); + m_radioViewRight->Enable(CompareMode); + m_radioViewLeft->SetValue(true); + /* remove the selection in the right listctrl (we only keep the left footprint) */ + RemoveSelection(m_listModulesRight, &SelectedPartRight); + PartData[1].Clear(); + /* check whether there is a selection in the left listctrl, only enable + the buttons if so */ + long idx = m_listModulesRight->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (idx >= 0) + EnableButtons(LEFTPANEL); + m_radioViewLeft->SetValue(true); + m_radioViewRight->SetValue(false); + } + + ModelMode = m_toolBar->GetToolToggled(IDT_3DVIEW); + if (ModelMode) { ScaleNormal = Scale; /* save the current value */ Scale = SCALE_DEFAULT; - m_panelView->SetBackgroundColour(clr3DModelMode); + m_panelView->SetBackgroundColour(clr3DModelMode); } else { - m_panelView->SetBackgroundColour(clrFootprintMode); + m_panelView->SetBackgroundColour(clrFootprintMode); sceneGraph.clear(); - if (glContext != NULL) - delete glContext; - if (glCanvas != NULL) { - glCanvas->Disconnect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(libmngrFrame::OnViewCentre), NULL, this); - glCanvas->Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(libmngrFrame::OnViewStartDrag), NULL, this); - glCanvas->Disconnect(wxEVT_MOTION, wxMouseEventHandler(libmngrFrame::OnViewDrag), NULL, this); - delete glCanvas; - } - glCanvas = NULL; - glContext = NULL; + if (glContext != NULL) + delete glContext; + if (glCanvas != NULL) { + glCanvas->Disconnect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(libmngrFrame::OnViewCentre), NULL, this); + glCanvas->Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(libmngrFrame::OnViewStartDrag), NULL, this); + glCanvas->Disconnect(wxEVT_MOTION, wxMouseEventHandler(libmngrFrame::OnViewDrag), NULL, this); + delete glCanvas; + } + glCanvas = NULL; + glContext = NULL; Scale = ScaleNormal; /* restore previous scale value */ - } + } - OffsetX = OffsetY = 0; - UpdateDetails(0); /* update details for the left component */ - if (ModelMode) { + OffsetX = OffsetY = 0; + UpdateDetails(0); /* update details for the left component */ + if (ModelMode) { sceneGraph.clear(); DrawModels(0, 0); /* only to create the canvas and the context, this is needed for loading the VRML file as well */ Update3DModel(PartData[0]); } - m_panelView->Refresh(); + m_panelView->Refresh(); #endif } void libmngrFrame::OnShowMeasurements(wxCommandEvent& /*event*/) { - m_panelView->Refresh(); + m_panelView->Refresh(); } void libmngrFrame::OnShowDetails(wxCommandEvent& /*event*/) { - bool details = m_toolBar->GetToolToggled(IDT_DETAILSPANEL); - m_menubar->Check(IDM_DETAILSPANEL, details); - ToggleDetailsPanel(details); + bool details = m_toolBar->GetToolToggled(IDT_DETAILSPANEL); + m_menubar->Check(IDM_DETAILSPANEL, details); + ToggleDetailsPanel(details); } void libmngrFrame::OnShowLabels(wxCommandEvent& /*event*/) { - m_panelView->Refresh(); + m_panelView->Refresh(); } void libmngrFrame::OnShowLeftFootprint(wxCommandEvent& /*event*/) { - m_panelView->Refresh(); + m_panelView->Refresh(); } void libmngrFrame::OnShowRightFootprint(wxCommandEvent& /*event*/) { - m_panelView->Refresh(); + m_panelView->Refresh(); } void libmngrFrame::OnShowLeftDetails(wxCommandEvent& /*event*/) { - UpdateDetails(0); + UpdateDetails(0); } void libmngrFrame::OnShowRightDetails(wxCommandEvent& /*event*/) { - UpdateDetails(1); + UpdateDetails(1); } void libmngrFrame::ToggleDetailsPanel(bool onoff) { - if (onoff && !m_splitterViewPanel->IsSplit()) { - m_panelSettings->Show(); - m_splitterViewPanel->SplitVertically(m_panelView, m_panelSettings, -PANEL_WIDTH); - } else if (!onoff && m_splitterViewPanel->IsSplit()) { - m_splitterViewPanel->Unsplit(); /* this implicitly hides the panel at the right */ - } + if (onoff && !m_splitterViewPanel->IsSplit()) { + m_panelSettings->Show(); + m_splitterViewPanel->SplitVertically(m_panelView, m_panelSettings, -PANEL_WIDTH); + } else if (!onoff && m_splitterViewPanel->IsSplit()) { + m_splitterViewPanel->Unsplit(); /* this implicitly hides the panel at the right */ + } } void libmngrFrame::EnableButtons(int side) { - bool valid = false; - int idx; - - switch (side) { - case LEFTPANEL: - idx = m_choiceModuleRight->GetCurrentSelection(); - if (idx >= 0 && idx < (int)m_choiceModuleRight->GetCount()) { - wxString target = m_choiceModuleRight->GetString(idx); - valid = (target[0] != '(') || target.CmpNoCase(LIB_REPOS) == 0; - idx = m_choiceModuleLeft->GetCurrentSelection(); - if (idx >= 0) { - wxString source = m_choiceModuleLeft->GetString(idx); - if (source.CmpNoCase(target) == 0) - valid = false; - } - } - m_btnMove->Enable(valid); - m_btnCopy->Enable(valid); - m_btnDelete->Enable(true); - m_btnRename->Enable(true); - m_btnDuplicate->Enable(true); - m_btnMove->SetLabel(wxT("&Move >>>")); - m_btnCopy->SetLabel(wxT("&Copy >>>")); - break; - case 0: - m_btnMove->Enable(false); - m_btnCopy->Enable(false); - m_btnDelete->Enable(false); - m_btnRename->Enable(false); - m_btnDuplicate->Enable(false); - m_btnMove->SetLabel(wxT("&Move")); - m_btnCopy->SetLabel(wxT("&Copy")); - break; - case RIGHTPANEL: - idx = m_choiceModuleLeft->GetCurrentSelection(); - if (idx >= 0 && idx < (int)m_choiceModuleLeft->GetCount()) { - wxString target = m_choiceModuleLeft->GetString(idx); - valid = (target[0] != '(') || target.CmpNoCase(LIB_REPOS) == 0; - idx = m_choiceModuleRight->GetCurrentSelection(); - if (idx >= 0) { - wxString source = m_choiceModuleRight->GetString(idx); - if (source.CmpNoCase(target) == 0) - valid = false; - } - } - m_btnMove->Enable(valid); - m_btnCopy->Enable(valid); - m_btnDelete->Enable(true); - m_btnRename->Enable(true); - m_btnDuplicate->Enable(true); - m_btnMove->SetLabel(wxT("<<< &Move")); - m_btnCopy->SetLabel(wxT("<<< &Copy")); - break; - default: - wxASSERT(false); - } + bool valid = false; + int idx; + + switch (side) { + case LEFTPANEL: + idx = m_choiceModuleRight->GetCurrentSelection(); + if (idx >= 0 && idx < (int)m_choiceModuleRight->GetCount()) { + wxString target = m_choiceModuleRight->GetString(idx); + valid = (target[0] != '(') || target.CmpNoCase(LIB_REPOS) == 0; + idx = m_choiceModuleLeft->GetCurrentSelection(); + if (idx >= 0) { + wxString source = m_choiceModuleLeft->GetString(idx); + if (source.CmpNoCase(target) == 0) + valid = false; + } + } + m_btnMove->Enable(valid); + m_btnCopy->Enable(valid); + m_btnDelete->Enable(true); + m_btnRename->Enable(true); + m_btnDuplicate->Enable(true); + m_btnMove->SetLabel(wxT("&Move >>>")); + m_btnCopy->SetLabel(wxT("&Copy >>>")); + break; + case 0: + m_btnMove->Enable(false); + m_btnCopy->Enable(false); + m_btnDelete->Enable(false); + m_btnRename->Enable(false); + m_btnDuplicate->Enable(false); + m_btnMove->SetLabel(wxT("&Move")); + m_btnCopy->SetLabel(wxT("&Copy")); + break; + case RIGHTPANEL: + idx = m_choiceModuleLeft->GetCurrentSelection(); + if (idx >= 0 && idx < (int)m_choiceModuleLeft->GetCount()) { + wxString target = m_choiceModuleLeft->GetString(idx); + valid = (target[0] != '(') || target.CmpNoCase(LIB_REPOS) == 0; + idx = m_choiceModuleRight->GetCurrentSelection(); + if (idx >= 0) { + wxString source = m_choiceModuleRight->GetString(idx); + if (source.CmpNoCase(target) == 0) + valid = false; + } + } + m_btnMove->Enable(valid); + m_btnCopy->Enable(valid); + m_btnDelete->Enable(true); + m_btnRename->Enable(true); + m_btnDuplicate->Enable(true); + m_btnMove->SetLabel(wxT("<<< &Move")); + m_btnCopy->SetLabel(wxT("<<< &Copy")); + break; + default: + wxASSERT(false); + } } /** GetSelection() returns the symbol/footprint name of the first (and only) @@ -4055,177 +4056,177 @@ void libmngrFrame::EnableButtons(int side) */ wxString libmngrFrame::GetSelection(wxListCtrl* list, wxChoice* choice, wxString* library, wxString* author) { - /* returns only the first selected item */ - long row = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - if (row == -1) - return wxEmptyString; - wxString symbol = list->GetItemText(row); - if (library) { - wxASSERT(choice); /* choice control must be known to retrieve the library */ - long idx = choice->GetCurrentSelection(); - wxASSERT(idx >= 0 && idx < (long)choice->GetCount()); - wxString source = choice->GetString(idx); - if (source.CmpNoCase(LIB_REPOS) == 0) { - *library = source; - if (author) { - wxListItem item; - item.SetId(row); - item.SetColumn(1); - item.SetMask(wxLIST_MASK_TEXT); - wxCHECK(list->GetItem(item), wxEmptyString); - *author = item.GetText(); - } - } else { - wxListItem item; - item.SetId(row); - item.SetColumn(2); - item.SetMask(wxLIST_MASK_TEXT); - wxCHECK(list->GetItem(item), wxEmptyString); - *library = item.GetText(); - if (author) - *author = wxEmptyString; - } - } - return symbol; + /* returns only the first selected item */ + long row = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (row == -1) + return wxEmptyString; + wxString symbol = list->GetItemText(row); + if (library) { + wxASSERT(choice); /* choice control must be known to retrieve the library */ + long idx = choice->GetCurrentSelection(); + wxASSERT(idx >= 0 && idx < (long)choice->GetCount()); + wxString source = choice->GetString(idx); + if (source.CmpNoCase(LIB_REPOS) == 0) { + *library = source; + if (author) { + wxListItem item; + item.SetId(row); + item.SetColumn(1); + item.SetMask(wxLIST_MASK_TEXT); + wxCHECK(list->GetItem(item), wxEmptyString); + *author = item.GetText(); + } + } else { + wxListItem item; + item.SetId(row); + item.SetColumn(2); + item.SetMask(wxLIST_MASK_TEXT); + wxCHECK(list->GetItem(item), wxEmptyString); + *library = item.GetText(); + if (author) + *author = wxEmptyString; + } + } + return symbol; } bool libmngrFrame::RemoveSelection(wxListCtrl* list, int* index) { - int count = 0; - long idx = -1; - for (;;) { - idx = list->GetNextItem(idx, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - if (idx == -1) - break; - #if defined _WIN32 - list->SetItemState(idx, 0, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED); - #else - list->SetItemState(idx, 0, wxLIST_STATE_SELECTED); - #endif - count++; - } - wxASSERT(index != NULL); - *index = -1; - return (count > 0); /* return true if a selection was indeed removed */ + int count = 0; + long idx = -1; + for (;;) { + idx = list->GetNextItem(idx, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (idx == -1) + break; + #if defined _WIN32 + list->SetItemState(idx, 0, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED); + #else + list->SetItemState(idx, 0, wxLIST_STATE_SELECTED); + #endif + count++; + } + wxASSERT(index != NULL); + *index = -1; + return (count > 0); /* return true if a selection was indeed removed */ } static int CompareStringNoCase(const wxString& first, const wxString& second) { - return first.CmpNoCase(second); + return first.CmpNoCase(second); } void libmngrFrame::CollectLibraries(const wxString &path, wxArrayString *list) { - wxDir dir(path); - if (!dir.IsOpened()) - return; /* error message already given */ - if (SymbolMode) { - dir.GetAllFiles(path, list, wxT("*.lib"), wxDIR_FILES); - dir.GetAllFiles(path, list, wxT("*.sym"), wxDIR_FILES); - } else { - dir.GetAllFiles(path, list, wxT("*.mod"), wxDIR_FILES); - dir.GetAllFiles(path, list, wxT("*.emp"), wxDIR_FILES); - dir.GetAllFiles(path, list, wxT("*.kicad_mod"), wxDIR_FILES); - /* collect s-expression libraries separately, because GetAllFiles() does not - return directories */ - wxString basename; - bool cont = dir.GetFirst(&basename, wxEmptyString, wxDIR_FILES | wxDIR_DIRS); - while (cont) { - wxFileName name(basename); - if (name.GetExt().CmpNoCase(wxT("pretty")) == 0) - list->Add(path + wxT(DIRSEP_STR) + basename); - cont = dir.GetNext(&basename); - } - } + wxDir dir(path); + if (!dir.IsOpened()) + return; /* error message already given */ + if (SymbolMode) { + dir.GetAllFiles(path, list, wxT("*.lib"), wxDIR_FILES); + dir.GetAllFiles(path, list, wxT("*.sym"), wxDIR_FILES); + } else { + dir.GetAllFiles(path, list, wxT("*.mod"), wxDIR_FILES); + dir.GetAllFiles(path, list, wxT("*.emp"), wxDIR_FILES); + dir.GetAllFiles(path, list, wxT("*.kicad_mod"), wxDIR_FILES); + /* collect s-expression libraries separately, because GetAllFiles() does not + return directories */ + wxString basename; + bool cont = dir.GetFirst(&basename, wxEmptyString, wxDIR_FILES | wxDIR_DIRS); + while (cont) { + wxFileName name(basename); + if (name.GetExt().CmpNoCase(wxT("pretty")) == 0) + list->Add(path + wxT(DIRSEP_STR) + basename); + cont = dir.GetNext(&basename); + } + } } void libmngrFrame::CollectAllLibraries(bool eraselists) { - #if defined _MSC_VER - _CrtCheckMemory(); - #endif - - wxArrayString list; - - wxFileConfig *config = new wxFileConfig(APP_NAME, VENDOR_NAME, theApp->GetINIPath()); - wxString path; - wxString key; - int idx = 1; - for ( ;; ) { - if (SymbolMode) - key = wxString::Format(wxT("paths/symbols%d"), idx); - else - key = wxString::Format(wxT("paths/footprints%d"), idx); - if (!config->Read(key, &path)) - break; - CollectLibraries(path, &list); - idx++; - } - delete config; - - list.Sort(CompareStringNoCase); - m_choiceModuleLeft->Clear(); - m_choiceModuleLeft->Append(LIB_NONE); - if (list.Count() > 0) - m_choiceModuleLeft->Append(LIB_ALL); - #if !defined NO_CURL - m_choiceModuleLeft->Append(LIB_REPOS); - #endif - if (list.Count() > 0) - m_choiceModuleLeft->Append(list); - m_choiceModuleLeft->SetSelection(0); - m_choiceModuleRight->Clear(); - m_choiceModuleRight->Append(LIB_NONE); - if (list.Count() > 0) - m_choiceModuleRight->Append(LIB_ALL); - #if !defined NO_CURL - m_choiceModuleRight->Append(LIB_REPOS); - #endif - if (list.Count() > 0) - m_choiceModuleRight->Append(list); - m_choiceModuleRight->SetSelection(0); - - if (eraselists) { - m_listModulesLeft->DeleteAllItems(); - m_listModulesRight->DeleteAllItems(); - PartData[0].Clear(); - PartData[1].Clear(); + #if defined _MSC_VER + _CrtCheckMemory(); + #endif + + wxArrayString list; + + wxFileConfig *config = new wxFileConfig(APP_NAME, VENDOR_NAME, theApp->GetINIPath()); + wxString path; + wxString key; + int idx = 1; + for ( ;; ) { + if (SymbolMode) + key = wxString::Format(wxT("paths/symbols%d"), idx); + else + key = wxString::Format(wxT("paths/footprints%d"), idx); + if (!config->Read(key, &path)) + break; + CollectLibraries(path, &list); + idx++; + } + delete config; + + list.Sort(CompareStringNoCase); + m_choiceModuleLeft->Clear(); + m_choiceModuleLeft->Append(LIB_NONE); + if (list.Count() > 0) + m_choiceModuleLeft->Append(LIB_ALL); + #if !defined NO_CURL + m_choiceModuleLeft->Append(LIB_REPOS); + #endif + if (list.Count() > 0) + m_choiceModuleLeft->Append(list); + m_choiceModuleLeft->SetSelection(0); + m_choiceModuleRight->Clear(); + m_choiceModuleRight->Append(LIB_NONE); + if (list.Count() > 0) + m_choiceModuleRight->Append(LIB_ALL); + #if !defined NO_CURL + m_choiceModuleRight->Append(LIB_REPOS); + #endif + if (list.Count() > 0) + m_choiceModuleRight->Append(list); + m_choiceModuleRight->SetSelection(0); + + if (eraselists) { + m_listModulesLeft->DeleteAllItems(); + m_listModulesRight->DeleteAllItems(); + PartData[0].Clear(); + PartData[1].Clear(); #if !defined NO_3DMODEL sceneGraph.clear(); #endif - } + } - #if defined _MSC_VER - _CrtCheckMemory(); - #endif + #if defined _MSC_VER + _CrtCheckMemory(); + #endif } void libmngrFrame::WarnNoRepository(wxChoice* choice) { - #if defined _MSC_VER - _CrtCheckMemory(); - #endif - - int idx = choice->GetCurrentSelection(); - if (idx < 0 || idx >= (int)choice->GetCount()) - return; - wxString path = choice->GetString(idx); - wxASSERT(path.length() > 0); - if (path.CmpNoCase(LIB_REPOS) != 0) - return; - /* so the repository is selected, check whether it was defined */ - #if defined NO_CURL - wxMessageBox(wxT("The repository functions are disabled in this version.")); - choice->SetSelection(0); - #else - wxFileConfig *config = new wxFileConfig(APP_NAME, VENDOR_NAME, theApp->GetINIPath()); - path = config->Read(wxT("repository/url")); - delete config; - if (path.Length() == 0) { - wxMessageBox(wxT("No repository is configured.\nPlease configure a repository before using it.")); - choice->SetSelection(0); - } - #endif + #if defined _MSC_VER + _CrtCheckMemory(); + #endif + + int idx = choice->GetCurrentSelection(); + if (idx < 0 || idx >= (int)choice->GetCount()) + return; + wxString path = choice->GetString(idx); + wxASSERT(path.length() > 0); + if (path.CmpNoCase(LIB_REPOS) != 0) + return; + /* so the repository is selected, check whether it was defined */ + #if defined NO_CURL + wxMessageBox(wxT("The repository functions are disabled in this version.")); + choice->SetSelection(0); + #else + wxFileConfig *config = new wxFileConfig(APP_NAME, VENDOR_NAME, theApp->GetINIPath()); + path = config->Read(wxT("repository/url")); + delete config; + if (path.Length() == 0) { + wxMessageBox(wxT("No repository is configured.\nPlease configure a repository before using it.")); + choice->SetSelection(0); + } + #endif } /* CompareNames() compares two strings with an algorithm that compares sequences @@ -4234,55 +4235,55 @@ void libmngrFrame::WarnNoRepository(wxChoice* choice) */ int libmngrFrame::CompareNames(const wxString& name1, const wxString& name2) { - int cmp = 0; - unsigned i1 = 0, i2 = 0; - while (i1 < name1.length() && i2 < name2.length() && cmp == 0) { - if (isdigit(name1[i1]) && isdigit(name2[i2])) { - unsigned l1, l2; - for (l1 = i1; l1 < name1.length() && (isdigit(name1[l1]) || name1[l1] == '.'); l1++) - /* nothing */; - for (l2 = i2; l2 < name2.length() && (isdigit(name2[l2]) || name2[l2] == '.'); l2++) - /* nothing */; - double v1, v2; - name1.Mid(i1, l1 - i1).ToDouble(&v1); - name2.Mid(i2, l2 - i2).ToDouble(&v2); - cmp = (long)((v2 - v1) * 1000); - i1 = l1; - i2 = l2; - } else { - cmp = toupper(name2[i2]) - toupper(name1[i1]); - i1++; - i2++; - } - } - if (cmp == 0) { - /* strings match up to the shortest length, check whether one of the two is longer */ - if (i1 < name1.length()) - cmp--; - if (i2 < name2.length()) - cmp++; - } - return cmp; + int cmp = 0; + unsigned i1 = 0, i2 = 0; + while (i1 < name1.length() && i2 < name2.length() && cmp == 0) { + if (isdigit(name1[i1]) && isdigit(name2[i2])) { + unsigned l1, l2; + for (l1 = i1; l1 < name1.length() && (isdigit(name1[l1]) || name1[l1] == '.'); l1++) + /* nothing */; + for (l2 = i2; l2 < name2.length() && (isdigit(name2[l2]) || name2[l2] == '.'); l2++) + /* nothing */; + double v1, v2; + name1.Mid(i1, l1 - i1).ToDouble(&v1); + name2.Mid(i2, l2 - i2).ToDouble(&v2); + cmp = (long)((v2 - v1) * 1000); + i1 = l1; + i2 = l2; + } else { + cmp = toupper(name2[i2]) - toupper(name1[i1]); + i1++; + i2++; + } + } + if (cmp == 0) { + /* strings match up to the shortest length, check whether one of the two is longer */ + if (i1 < name1.length()) + cmp--; + if (i2 < name2.length()) + cmp++; + } + return cmp; } long libmngrFrame::GetListPosition(const wxString &name, const wxListCtrl* list) { - long low, high; - low = 0; - high = list->GetItemCount() - 1; - while (low <= high) { - long mid = (low + high) / 2; - wxString item = list->GetItemText(mid); - /* use a comparison algorithm that compares sequences of digits - separately from sequences of other characters; so that SOIC8 - comes before SOIC10 */ - int cmp = CompareNames(name, item); - if (cmp >= 0) - high = mid - 1; - else - low = mid + 1; - } - return low; + long low, high; + low = 0; + high = list->GetItemCount() - 1; + while (low <= high) { + long mid = (low + high) / 2; + wxString item = list->GetItemText(mid); + /* use a comparison algorithm that compares sequences of digits + separately from sequences of other characters; so that SOIC8 + comes before SOIC10 */ + int cmp = CompareNames(name, item); + if (cmp >= 0) + high = mid - 1; + else + low = mid + 1; + } + return low; } /* HandleLibrarySelect() updates the module list for the given side (in "choice" and "list). @@ -4292,207 +4293,207 @@ long libmngrFrame::GetListPosition(const wxString &name, const wxListCtrl* list) */ void libmngrFrame::HandleLibrarySelect(wxChoice* choice, wxListCtrl* list, int side) { - #if defined _MSC_VER - _CrtCheckMemory(); - #endif - CheckSavePart(); - - wxASSERT(side >= LEFTPANEL && side <= RIGHTPANEL); /* -1 = left, 1 = right, 0 = both */ - int idx = choice->GetCurrentSelection(); - if (idx < 0 || idx >= (int)choice->GetCount()) - return; - - FieldEdited = false; - PartEdited = false; - - /* make sure to clear any component in the viewport */ - if (CompareMode) { - if (side == BOTHPANELS || side == RIGHTPANEL) { - PartData[1].Clear(); - UpdateDetails(1); - } else { - PartData[0].Clear(); - UpdateDetails(0); - } - } else { - PartData[0].Clear(); - UpdateDetails(0); - } + #if defined _MSC_VER + _CrtCheckMemory(); + #endif + CheckSavePart(); + + wxASSERT(side >= LEFTPANEL && side <= RIGHTPANEL); /* -1 = left, 1 = right, 0 = both */ + int idx = choice->GetCurrentSelection(); + if (idx < 0 || idx >= (int)choice->GetCount()) + return; + + FieldEdited = false; + PartEdited = false; + + /* make sure to clear any component in the viewport */ + if (CompareMode) { + if (side == BOTHPANELS || side == RIGHTPANEL) { + PartData[1].Clear(); + UpdateDetails(1); + } else { + PartData[0].Clear(); + UpdateDetails(0); + } + } else { + PartData[0].Clear(); + UpdateDetails(0); + } #if !defined NO_3DMODEL sceneGraph.clear(); #endif - if (side == LEFTPANEL || side == BOTHPANELS) { - if (RemoveSelection(m_listModulesLeft, &SelectedPartLeft)) - EnableButtons(0); - } - if (side == RIGHTPANEL || side == BOTHPANELS) { - if (RemoveSelection(m_listModulesRight, &SelectedPartRight)) - EnableButtons(0); - } - - list->DeleteAllItems(); - wxString filename = choice->GetString(idx); - wxASSERT(filename.length() > 0); - if (filename.CmpNoCase(LIB_NONE) == 0) - return; - - wxString filter = wxEmptyString; - if (m_editFilter->IsShown()) { - filter = m_editFilter->GetValue(); - filter.Trim(false); - filter.Trim(true); - filter.MakeLower(); - } + if (side == LEFTPANEL || side == BOTHPANELS) { + if (RemoveSelection(m_listModulesLeft, &SelectedPartLeft)) + EnableButtons(0); + } + if (side == RIGHTPANEL || side == BOTHPANELS) { + if (RemoveSelection(m_listModulesRight, &SelectedPartRight)) + EnableButtons(0); + } + + list->DeleteAllItems(); + wxString filename = choice->GetString(idx); + wxASSERT(filename.length() > 0); + if (filename.CmpNoCase(LIB_NONE) == 0) + return; + + wxString filter = wxEmptyString; + if (m_editFilter->IsShown()) { + filter = m_editFilter->GetValue(); + filter.Trim(false); + filter.Trim(true); + filter.MakeLower(); + } wxString title = SymbolMode ? wxT("Collecting symbols") : wxT("Collecting footprints"); wxString msg = (filter.Length() > 0) ? wxT("Filtering library, please wait...") : wxT("Please wait..."); wxProgressDialog* progress = new wxProgressDialog(title, msg, 100, this, wxPD_APP_MODAL|wxPD_AUTO_HIDE|wxPD_ELAPSED_TIME|wxPD_ESTIMATED_TIME|wxPD_REMAINING_TIME); - if (filename.CmpNoCase(LIB_ALL) == 0) { + if (filename.CmpNoCase(LIB_ALL) == 0) { progress->SetRange(choice->GetCount() - 1); - for (idx = 0; idx < (int)choice->GetCount(); idx++) { - wxString filename = choice->GetString(idx); - wxASSERT(filename.length() > 0); - if (filename.CmpNoCase(LIB_NONE) == 0 || filename.CmpNoCase(LIB_ALL) == 0 || filename.CmpNoCase(LIB_REPOS) == 0) - continue; - if (SymbolMode) - CollectSymbols(filename, list, filter); - else - CollectFootprints(filename, list, filter); + for (idx = 0; idx < (int)choice->GetCount(); idx++) { + wxString filename = choice->GetString(idx); + wxASSERT(filename.length() > 0); + if (filename.CmpNoCase(LIB_NONE) == 0 || filename.CmpNoCase(LIB_ALL) == 0 || filename.CmpNoCase(LIB_REPOS) == 0) + continue; + if (SymbolMode) + CollectSymbols(filename, list, filter); + else + CollectFootprints(filename, list, filter); progress->Update(idx); - } - } else if (filename.CmpNoCase(LIB_REPOS) == 0) { - #if defined NO_CURL - wxMessageBox(wxT("The repository functions are disabled in this version.")); - #else - wxArrayString data; - wxString msg = curlList(&data, SymbolMode ? wxT("symbols") : wxT("footprints"), filter); - if (msg.length() == 0) { - for (unsigned idx = 0; idx < data.Count(); idx++) { - wxString line = data[idx]; - int pos = line.Find(wxT('\t')); - if (pos <= 0) - continue; - wxString name = line.Left(pos); - wxString lname = name.Lower(); - long insertpos = GetListPosition(name, list); - long item = list->InsertItem(insertpos, name); - list->SetItem(item, 1, line.Mid(pos + 1)); - list->SetItem(item, 2, wxEmptyString); /* no full path for the repository */ - } - } else { - wxMessageBox(wxT("Error listing repository\n\nRepository message: ") + msg); - } - #endif - } else { - if (SymbolMode) - CollectSymbols(filename, list, filter, progress); - else - CollectFootprints(filename, list, filter, progress); - } - - list->SetColumnWidth(0, wxLIST_AUTOSIZE); - list->SetColumnWidth(1, wxLIST_AUTOSIZE); - list->SetColumnWidth(2, 0); /* add an invisible column for the full path to the library */ - /* column widths are sometimes a few pixels off, so here is a kludge */ - list->SetColumnWidth(0, list->GetColumnWidth(0) + 2); - list->SetColumnWidth(1, list->GetColumnWidth(1) + 2); + } + } else if (filename.CmpNoCase(LIB_REPOS) == 0) { + #if defined NO_CURL + wxMessageBox(wxT("The repository functions are disabled in this version.")); + #else + wxArrayString data; + wxString msg = curlList(&data, SymbolMode ? wxT("symbols") : wxT("footprints"), filter); + if (msg.length() == 0) { + for (unsigned idx = 0; idx < data.Count(); idx++) { + wxString line = data[idx]; + int pos = line.Find(wxT('\t')); + if (pos <= 0) + continue; + wxString name = line.Left(pos); + wxString lname = name.Lower(); + long insertpos = GetListPosition(name, list); + long item = list->InsertItem(insertpos, name); + list->SetItem(item, 1, line.Mid(pos + 1)); + list->SetItem(item, 2, wxEmptyString); /* no full path for the repository */ + } + } else { + wxMessageBox(wxT("Error listing repository\n\nRepository message: ") + msg); + } + #endif + } else { + if (SymbolMode) + CollectSymbols(filename, list, filter, progress); + else + CollectFootprints(filename, list, filter, progress); + } + + list->SetColumnWidth(0, wxLIST_AUTOSIZE); + list->SetColumnWidth(1, wxLIST_AUTOSIZE); + list->SetColumnWidth(2, 0); /* add an invisible column for the full path to the library */ + /* column widths are sometimes a few pixels off, so here is a kludge */ + list->SetColumnWidth(0, list->GetColumnWidth(0) + 2); + list->SetColumnWidth(1, list->GetColumnWidth(1) + 2); delete progress; - if (SymbolMode) - msg = wxString::Format(wxT("Loaded %d symbols"), list->GetItemCount()); - else - msg = wxString::Format(wxT("Loaded %d footprints"), list->GetItemCount()); - m_statusBar->SetStatusText(msg); + if (SymbolMode) + msg = wxString::Format(wxT("Loaded %d symbols"), list->GetItemCount()); + else + msg = wxString::Format(wxT("Loaded %d footprints"), list->GetItemCount()); + m_statusBar->SetStatusText(msg); if (SelectedPartLeft >= m_listModulesLeft->GetItemCount()) SelectedPartLeft = -1; if (SelectedPartRight >= m_listModulesRight->GetItemCount()) SelectedPartRight = -1; - if (side == RIGHTPANEL && SelectedPartLeft >= 0) { - LoadPart(SelectedPartLeft, m_listModulesLeft, m_choiceModuleLeft, 0); - UpdateDetails(0); + if (side == RIGHTPANEL && SelectedPartLeft >= 0) { + LoadPart(SelectedPartLeft, m_listModulesLeft, m_choiceModuleLeft, 0); + UpdateDetails(0); Update3DModel(PartData[0]); - m_panelView->Refresh(); - } else if (side == LEFTPANEL && SelectedPartRight >= 0) { - LoadPart(SelectedPartRight, m_listModulesRight, m_choiceModuleRight, CompareMode ? 1 : 0); - UpdateDetails(CompareMode ? 1 : 0); + m_panelView->Refresh(); + } else if (side == LEFTPANEL && SelectedPartRight >= 0) { + LoadPart(SelectedPartRight, m_listModulesRight, m_choiceModuleRight, CompareMode ? 1 : 0); + UpdateDetails(CompareMode ? 1 : 0); if (!CompareMode) Update3DModel(PartData[0]); - m_panelView->Refresh(); - } + m_panelView->Refresh(); + } } void libmngrFrame::CollectSymbols(const wxString &path, wxListCtrl* list, const wxString& filter, wxProgressDialog* progress) { - wxString libname; - if (ShowFullPaths) { - libname = path; - } else { - wxFileName fname(path); - libname = fname.GetFullName(); - } + wxString libname; + if (ShowFullPaths) { + libname = path; + } else { + wxFileName fname(path); + libname = fname.GetFullName(); + } - wxTextFile file; - if (!file.Open(path)) { - wxMessageBox(wxT("Failed to open symbol library ") + path); - return; - } + wxTextFile file; + if (!file.Open(path)) { + wxMessageBox(wxT("Failed to open symbol library ") + path); + return; + } if (progress) progress->SetRange(file.GetLineCount() - 1); - /* verify the header */ - wxString line = file.GetLine(0); - if (line.Left(16).CmpNoCase(wxT("EESchema-LIBRARY")) != 0 - && line.Left(13).CmpNoCase(wxT("EESchema-LIB ")) != 0) - { - wxMessageBox(wxT("Symbol library ") + path + wxT(" has an unsupported format.")); - file.Close(); - return; - } - m_statusBar->SetStatusText(wxT("Scanning ") + path); - - /* collect the symbol definitions in the file */ - for (unsigned idx = 1; idx < file.GetLineCount(); idx++) { - line = file.GetLine(idx); - if (line[0] == wxT('D') && line.Left(4).Cmp(wxT("DEF ")) == 0) { - line = line.Mid(4); - wxString name = GetToken(&line); - /* remove leading tilde, this is an "non-visible" flag */ - if (name[0] == wxT('~')) - name = name.Mid(1); - bool match = true; - if (filter.Length() > 0) { - match = false; - wxString lname = name.Lower(); - if (lname.Find(filter) >= 0) - match = true; - wxArrayString symbol; - if (!match && LoadSymbol(path, name, wxEmptyString, false, &symbol)) { - wxString field = GetDescription(symbol, true); - field.MakeLower(); - if (line.Find(filter) >= 0) - match = true; - field = GetAliases(symbol); - field.MakeLower(); - if (line.Find(filter) >= 0) - match = true; - } - } - if (!match) - continue; - long insertpos = GetListPosition(name, list); - long item = list->InsertItem(insertpos, name); - list->SetItem(item, 1, libname); - list->SetItem(item, 2, path); - } + /* verify the header */ + wxString line = file.GetLine(0); + if (line.Left(16).CmpNoCase(wxT("EESchema-LIBRARY")) != 0 + && line.Left(13).CmpNoCase(wxT("EESchema-LIB ")) != 0) + { + wxMessageBox(wxT("Symbol library ") + path + wxT(" has an unsupported format.")); + file.Close(); + return; + } + m_statusBar->SetStatusText(wxT("Scanning ") + path); + + /* collect the symbol definitions in the file */ + for (unsigned idx = 1; idx < file.GetLineCount(); idx++) { + line = file.GetLine(idx); + if (line[0] == wxT('D') && line.Left(4).Cmp(wxT("DEF ")) == 0) { + line = line.Mid(4); + wxString name = GetToken(&line); + /* remove leading tilde, this is an "non-visible" flag */ + if (name[0] == wxT('~')) + name = name.Mid(1); + bool match = true; + if (filter.Length() > 0) { + match = false; + wxString lname = name.Lower(); + if (lname.Find(filter) >= 0) + match = true; + wxArrayString symbol; + if (!match && LoadSymbol(path, name, wxEmptyString, false, &symbol)) { + wxString field = GetDescription(symbol, true); + field.MakeLower(); + if (line.Find(filter) >= 0) + match = true; + field = GetAliases(symbol); + field.MakeLower(); + if (line.Find(filter) >= 0) + match = true; + } + } + if (!match) + continue; + long insertpos = GetListPosition(name, list); + long item = list->InsertItem(insertpos, name); + list->SetItem(item, 1, libname); + list->SetItem(item, 2, path); + } if (progress) progress->Update(idx); - } + } - file.Close(); + file.Close(); } bool libmngrFrame::MatchFootprint(const wxString& libname, const wxString& symname, const wxString& filter) @@ -4526,14 +4527,14 @@ bool libmngrFrame::MatchFootprint(const wxString& libname, const wxString& symna if (rc == UNQLITE_NOTFOUND) store_symbol = true; /* key was not found, must store */ } - + if (store_symbol) { - wxArrayString footprint; - int version; - if (LoadFootprint(libname, symname, wxEmptyString, false, &footprint, &version)) { + wxArrayString footprint; + int version; + if (LoadFootprint(libname, symname, wxEmptyString, false, &footprint, &version)) { unqlite_close(pDb); /* close the database, for caching the data */ - FootprintInfo fp(version); - TranslatePadInfo(&footprint, &fp); + FootprintInfo fp(version); + TranslatePadInfo(&footprint, &fp); CacheMetadata(libname, symname, true, footprint, fp); /* re-open the database */ rc = unqlite_open(&pDb, path.c_str(), UNQLITE_OPEN_CREATE); @@ -4560,7 +4561,7 @@ bool libmngrFrame::MatchFootprint(const wxString& libname, const wxString& symna unqlite_close(pDb); /* extract fields from the metadata */ - wxString keywords = symname.Lower(); /* footprint name is matched on too */ + wxString keywords = symname.Lower(); /* footprint name is matched on too */ wxString pins = wxEmptyString; wxString pitch = wxEmptyString; wxString span = wxEmptyString; @@ -4590,7 +4591,7 @@ bool libmngrFrame::MatchFootprint(const wxString& libname, const wxString& symna token.AfterFirst(wxT(':')).ToLong(&count); long nonregpins = 0, regularpins = 0; pins.ToLong(®ularpins); - if (pins.Find(wxT('+')) > 0) + if (pins.Find(wxT('+')) > 0) pins.AfterFirst(wxT('+')).ToLong(&nonregpins); match = (count == regularpins || count == regularpins + nonregpins); } else if (token.Left(6).Cmp(wxT("pitch:")) == 0) { @@ -4600,8 +4601,8 @@ bool libmngrFrame::MatchFootprint(const wxString& libname, const wxString& symna token = token.AfterFirst(wxT(':')); match = span.Left(token.Length()).Cmp(token) == 0; } else { - if (keywords.Find(token) >= 0) - match = true; + if (keywords.Find(token) >= 0) + match = true; } allmatch = allmatch && match; } @@ -4611,1445 +4612,1445 @@ bool libmngrFrame::MatchFootprint(const wxString& libname, const wxString& symna void libmngrFrame::CollectFootprints(const wxString &path, wxListCtrl* list, const wxString& filter, wxProgressDialog* progress) { - wxFileName fname(path); - wxString libname = ShowFullPaths ? path : fname.GetFullName(); + wxFileName fname(path); + wxString libname = ShowFullPaths ? path : fname.GetFullName(); - if (wxFileName::DirExists(path)) { - m_statusBar->SetStatusText(wxT("Scanning ") + path); - wxDir dir(path); - if (!dir.IsOpened()) - return; /* error message already given */ - wxArrayString modlist; - dir.GetAllFiles(path, &modlist, wxT("*.kicad_mod"), wxDIR_FILES); + if (wxFileName::DirExists(path)) { + m_statusBar->SetStatusText(wxT("Scanning ") + path); + wxDir dir(path); + if (!dir.IsOpened()) + return; /* error message already given */ + wxArrayString modlist; + dir.GetAllFiles(path, &modlist, wxT("*.kicad_mod"), wxDIR_FILES); if (progress) progress->SetRange(modlist.Count() - 1); - for (unsigned idx = 0; idx < modlist.Count(); idx++) { - wxFileName modfile(modlist[idx]); - wxString name = modfile.GetName(); - if (MatchFootprint(path, name, filter)) { - long insertpos = GetListPosition(name, list); - long item = list->InsertItem(insertpos, name); - list->SetItem(item, 1, libname); - list->SetItem(item, 2, path); + for (unsigned idx = 0; idx < modlist.Count(); idx++) { + wxFileName modfile(modlist[idx]); + wxString name = modfile.GetName(); + if (MatchFootprint(path, name, filter)) { + long insertpos = GetListPosition(name, list); + long item = list->InsertItem(insertpos, name); + list->SetItem(item, 1, libname); + list->SetItem(item, 2, path); } if (progress) progress->Update(idx); } - } else if (fname.GetExt().Cmp(wxT("kicad_mod")) == 0) { - wxString name = fname.GetName(); - if (MatchFootprint(path, name, filter)) { - long insertpos = GetListPosition(name, list); - long item = list->InsertItem(insertpos, name); - list->SetItem(item, 1, libname); - list->SetItem(item, 2, path); - } - } else { - wxTextFile file; - if (!file.Open(path)) { - wxMessageBox(wxT("Failed to open footprint library ") + path); - return; - } - - /* verify the header */ - wxString line = file.GetLine(0); - line = line.Left(19); - if (line.CmpNoCase(wxT("PCBNEW-LibModule-V1")) != 0) { - wxMessageBox(wxT("Footprint library ") + path + wxT(" has an unsupported format.")); - file.Close(); - return; - } - m_statusBar->SetStatusText(wxT("Scanning ") + path); - - /* search the index */ - unsigned idx = 1; - while (idx < file.GetLineCount()) { - line = file.GetLine(idx); - idx++; - if (line.CmpNoCase(wxT("$INDEX")) == 0) - break; - } + } else if (fname.GetExt().Cmp(wxT("kicad_mod")) == 0) { + wxString name = fname.GetName(); + if (MatchFootprint(path, name, filter)) { + long insertpos = GetListPosition(name, list); + long item = list->InsertItem(insertpos, name); + list->SetItem(item, 1, libname); + list->SetItem(item, 2, path); + } + } else { + wxTextFile file; + if (!file.Open(path)) { + wxMessageBox(wxT("Failed to open footprint library ") + path); + return; + } + + /* verify the header */ + wxString line = file.GetLine(0); + line = line.Left(19); + if (line.CmpNoCase(wxT("PCBNEW-LibModule-V1")) != 0) { + wxMessageBox(wxT("Footprint library ") + path + wxT(" has an unsupported format.")); + file.Close(); + return; + } + m_statusBar->SetStatusText(wxT("Scanning ") + path); + + /* search the index */ + unsigned idx = 1; + while (idx < file.GetLineCount()) { + line = file.GetLine(idx); + idx++; + if (line.CmpNoCase(wxT("$INDEX")) == 0) + break; + } /* find the end of the index */ unsigned tail = idx; while (tail < file.GetLineCount()) { - line = file.GetLine(tail); - if (line.CmpNoCase(wxT("$EndINDEX")) == 0) - break; + line = file.GetLine(tail); + if (line.CmpNoCase(wxT("$EndINDEX")) == 0) + break; tail++; } - /* read the modules (browse through the index) */ + /* read the modules (browse through the index) */ if (progress) { progress->SetRange(tail - 1); wxASSERT(idx > 0); progress->Update(idx - 1); } - while (idx < tail) { - line = file.GetLine(idx); - wxASSERT(line.CmpNoCase(wxT("$EndINDEX")) != 0); - if (MatchFootprint(path, line, filter)) { - long insertpos = GetListPosition(line, list); - long item = list->InsertItem(insertpos, line); - list->SetItem(item, 1, libname); - list->SetItem(item, 2, path); - } + while (idx < tail) { + line = file.GetLine(idx); + wxASSERT(line.CmpNoCase(wxT("$EndINDEX")) != 0); + if (MatchFootprint(path, line, filter)) { + long insertpos = GetListPosition(line, list); + long item = list->InsertItem(insertpos, line); + list->SetItem(item, 1, libname); + list->SetItem(item, 2, path); + } if (progress) progress->Update(idx); - idx++; - } + idx++; + } - file.Close(); - } + file.Close(); + } } void libmngrFrame::SynchronizeLibraries(wxListCtrl* list1, wxListCtrl* list2) { - if (!SyncMode || list1->GetItemCount() == 0 || list2->GetItemCount() == 0) - return; /* don't synchronize if one of the lists is empty */ - - /* first pass, remove phantom entries in both lists */ - for (int pass = 0; pass < 2; pass++) { - wxListCtrl* list = (pass == 0) ? list1 : list2; - long row = 0; - while (row < list->GetItemCount()) { - wxListItem info; - info.SetId(row); - info.SetColumn(1); - info.SetMask(wxLIST_MASK_TEXT); - list->GetItem(info); - if (info.GetText().Length() == 0) - list->DeleteItem(row); - else - row++; - } - } - - /* second pass, synchronize by adding phantom entries */ - long row = 0; - while (row < list1->GetItemCount() || row < list2->GetItemCount()) { - wxString sym1 = (row < list1->GetItemCount()) ? list1->GetItemText(row) : (wxString)wxEmptyString; - wxString sym2 = (row < list2->GetItemCount()) ? list2->GetItemText(row) : (wxString)wxEmptyString; - wxASSERT(sym1.Length() > 0 || sym2.Length() > 0); - int cmp; - if (sym1.Length() == 0) - cmp = -1; /* always copy from right to left when the left element is missing */ - else if (sym2.Length() == 0) - cmp = 1; - else - cmp = CompareNames(sym1, sym2); - if (cmp != 0) { - /* mismatch on the names (a symbol in one list does not appear in the other) */ - wxListCtrl *list = NULL; - wxString name; - if (cmp < 0) { - /* insert symbol from the right list into the left list */ - list = list1; - name = sym2; - } else if (cmp > 0) { - /* insert symbol from the left list into the right list */ - list = list2; - name = sym1; - } - wxASSERT(list != NULL); - long insertpos = GetListPosition(name, list); - long item = list->InsertItem(insertpos, name); - list->SetItemTextColour(item, wxColour(160,96,96)); - } - row++; - } + if (!SyncMode || list1->GetItemCount() == 0 || list2->GetItemCount() == 0) + return; /* don't synchronize if one of the lists is empty */ + + /* first pass, remove phantom entries in both lists */ + for (int pass = 0; pass < 2; pass++) { + wxListCtrl* list = (pass == 0) ? list1 : list2; + long row = 0; + while (row < list->GetItemCount()) { + wxListItem info; + info.SetId(row); + info.SetColumn(1); + info.SetMask(wxLIST_MASK_TEXT); + list->GetItem(info); + if (info.GetText().Length() == 0) + list->DeleteItem(row); + else + row++; + } + } + + /* second pass, synchronize by adding phantom entries */ + long row = 0; + while (row < list1->GetItemCount() || row < list2->GetItemCount()) { + wxString sym1 = (row < list1->GetItemCount()) ? list1->GetItemText(row) : (wxString)wxEmptyString; + wxString sym2 = (row < list2->GetItemCount()) ? list2->GetItemText(row) : (wxString)wxEmptyString; + wxASSERT(sym1.Length() > 0 || sym2.Length() > 0); + int cmp; + if (sym1.Length() == 0) + cmp = -1; /* always copy from right to left when the left element is missing */ + else if (sym2.Length() == 0) + cmp = 1; + else + cmp = CompareNames(sym1, sym2); + if (cmp != 0) { + /* mismatch on the names (a symbol in one list does not appear in the other) */ + wxListCtrl *list = NULL; + wxString name; + if (cmp < 0) { + /* insert symbol from the right list into the left list */ + list = list1; + name = sym2; + } else if (cmp > 0) { + /* insert symbol from the left list into the right list */ + list = list2; + name = sym1; + } + wxASSERT(list != NULL); + long insertpos = GetListPosition(name, list); + long item = list->InsertItem(insertpos, name); + list->SetItemTextColour(item, wxColour(160,96,96)); + } + row++; + } } void libmngrFrame::LoadPart(int index, wxListCtrl* list, wxChoice* choice, int fp) { - m_statusBar->SetStatusText(wxEmptyString); - PartData[fp].Clear(); - - /* get the name of the symbol and the library it is in */ - wxString symbol = list->GetItemText(index); - wxASSERT(symbol.length() > 0); - wxString author = wxEmptyString; - wxString filename = wxEmptyString; - /* also check the library selection, in the case of the repository, - the user name is in column 1 (instead of the filename) */ - if (choice) { - long libidx = choice->GetSelection(); - wxASSERT(libidx >= 0 && libidx < (long)choice->GetCount()); - filename = choice->GetString(libidx); - } - - /* in case the module lists are synchronized, the user may click on an item that - is not in the library */ - if (SyncMode) { - wxListItem info; - info.SetId(index); - info.SetColumn(1); - info.SetMask(wxLIST_MASK_TEXT); - list->GetItem(info); - if (info.GetText().Length() == 0) { - /* clear everything and quit */ - Footprint[fp].Clear(VER_INVALID); - BodySize[fp].Clear(); - LabelData[fp].Clear(); - if (PinData[fp] != NULL) { - delete[] PinData[fp]; - PinData[fp] = 0; - PinDataCount[fp] = 0; - } - FieldEdited = false; - PartEdited = false; - PinNamesEdited = false; - return; - } - } - - if (filename.CmpNoCase(LIB_REPOS) == 0) { - FromRepository[fp] = true; - wxListItem info; - info.SetId(index); - info.SetColumn(1); - info.SetMask(wxLIST_MASK_TEXT); - list->GetItem(info); - author = info.GetText(); - } else { - FromRepository[fp] = false; - wxListItem info; - info.SetId(index); - info.SetColumn(2); - info.SetMask(wxLIST_MASK_TEXT); - list->GetItem(info); - filename = info.GetText(); - } - - int version = VER_INVALID; - if (SymbolMode) { - if (!LoadSymbol(filename, symbol, author, DontRebuildTemplate, &PartData[fp])) { - wxTextFile file; - if (!file.Open(filename)) - wxMessageBox(wxT("Failed to open library ") + filename); - else - wxMessageBox(wxT("Symbol ") + symbol + wxT(" is not present.")); - } - } else { - if (!LoadFootprint(filename, symbol, author, DontRebuildTemplate, &PartData[fp], &version)) { - /* check what the error is */ - wxTextFile file; - if (!wxFileName::DirExists(filename) && !file.Open(filename)) - wxMessageBox(wxT("Failed to open library ") + filename); - else if (version == VER_INVALID) - wxMessageBox(wxT("Library ") + filename + wxT(" has an unsupported format.")); - else - wxMessageBox(wxT("Footprint ") + symbol + wxT(" is not present.")); - return; - } - } - - /* verify that the symbol/footprint was actually found */ - wxASSERT(PartData[fp].Count() > 0); - - Footprint[fp].Clear(version); - BodySize[fp].Clear(); - LabelData[fp].Clear(); - if (PinData[fp] != NULL) { - delete[] PinData[fp]; - PinData[fp] = 0; - PinDataCount[fp] = 0; - } - if (SymbolMode) { - /* extract pin names and order */ - GetPinNames(PartData[fp], NULL, &PinDataCount[fp]); - if (PinDataCount[fp] > 0) { - PinData[fp] = new PinInfo[PinDataCount[fp]]; - wxASSERT(PinData[fp] != NULL); - GetPinNames(PartData[fp], PinData[fp], NULL); - } - } else { - /* get the pin pitch and pad size, plus the body size */ - Footprint[fp].Type = version; - TranslatePadInfo(&PartData[fp], &Footprint[fp]); + m_statusBar->SetStatusText(wxEmptyString); + PartData[fp].Clear(); + + /* get the name of the symbol and the library it is in */ + wxString symbol = list->GetItemText(index); + wxASSERT(symbol.length() > 0); + wxString author = wxEmptyString; + wxString filename = wxEmptyString; + /* also check the library selection, in the case of the repository, + the user name is in column 1 (instead of the filename) */ + if (choice) { + long libidx = choice->GetSelection(); + wxASSERT(libidx >= 0 && libidx < (long)choice->GetCount()); + filename = choice->GetString(libidx); + } + + /* in case the module lists are synchronized, the user may click on an item that + is not in the library */ + if (SyncMode) { + wxListItem info; + info.SetId(index); + info.SetColumn(1); + info.SetMask(wxLIST_MASK_TEXT); + list->GetItem(info); + if (info.GetText().Length() == 0) { + /* clear everything and quit */ + Footprint[fp].Clear(VER_INVALID); + BodySize[fp].Clear(); + LabelData[fp].Clear(); + if (PinData[fp] != NULL) { + delete[] PinData[fp]; + PinData[fp] = 0; + PinDataCount[fp] = 0; + } + FieldEdited = false; + PartEdited = false; + PinNamesEdited = false; + return; + } + } + + if (filename.CmpNoCase(LIB_REPOS) == 0) { + FromRepository[fp] = true; + wxListItem info; + info.SetId(index); + info.SetColumn(1); + info.SetMask(wxLIST_MASK_TEXT); + list->GetItem(info); + author = info.GetText(); + } else { + FromRepository[fp] = false; + wxListItem info; + info.SetId(index); + info.SetColumn(2); + info.SetMask(wxLIST_MASK_TEXT); + list->GetItem(info); + filename = info.GetText(); + } + + int version = VER_INVALID; + if (SymbolMode) { + if (!LoadSymbol(filename, symbol, author, DontRebuildTemplate, &PartData[fp])) { + wxTextFile file; + if (!file.Open(filename)) + wxMessageBox(wxT("Failed to open library ") + filename); + else + wxMessageBox(wxT("Symbol ") + symbol + wxT(" is not present.")); + } + } else { + if (!LoadFootprint(filename, symbol, author, DontRebuildTemplate, &PartData[fp], &version)) { + /* check what the error is */ + wxTextFile file; + if (!wxFileName::DirExists(filename) && !file.Open(filename)) + wxMessageBox(wxT("Failed to open library ") + filename); + else if (version == VER_INVALID) + wxMessageBox(wxT("Library ") + filename + wxT(" has an unsupported format.")); + else + wxMessageBox(wxT("Footprint ") + symbol + wxT(" is not present.")); + return; + } + } + + /* verify that the symbol/footprint was actually found */ + wxASSERT(PartData[fp].Count() > 0); + + Footprint[fp].Clear(version); + BodySize[fp].Clear(); + LabelData[fp].Clear(); + if (PinData[fp] != NULL) { + delete[] PinData[fp]; + PinData[fp] = 0; + PinDataCount[fp] = 0; + } + if (SymbolMode) { + /* extract pin names and order */ + GetPinNames(PartData[fp], NULL, &PinDataCount[fp]); + if (PinDataCount[fp] > 0) { + PinData[fp] = new PinInfo[PinDataCount[fp]]; + wxASSERT(PinData[fp] != NULL); + GetPinNames(PartData[fp], PinData[fp], NULL); + } + } else { + /* get the pin pitch and pad size, plus the body size */ + Footprint[fp].Type = version; + TranslatePadInfo(&PartData[fp], &Footprint[fp]); /* optionally cache the metadata (pitch, courtyard, descriptions) */ CacheMetadata(filename, symbol, false, PartData[fp], Footprint[fp]); } - GetBodySize(PartData[fp], &BodySize[fp], SymbolMode, Footprint[fp].Type >= VER_MM); - GetTextLabelSize(PartData[fp], &LabelData[fp], SymbolMode, Footprint[fp].Type >= VER_MM); - if (SymbolMode) { - /* re-assign the pins to custom sections (now that the body size is known) */ - wxString templatename = GetTemplateName(PartData[fp]); - GetTemplateSections(templatename, CustomPinSections[fp], sizearray(CustomPinSections[fp])); - ReAssignPins(PinData[fp], PinDataCount[fp], BodySize[fp], CustomPinSections[fp], sizearray(CustomPinSections[fp])); - } - FieldEdited = false; - PartEdited = false; - PinNamesEdited = false; + GetBodySize(PartData[fp], &BodySize[fp], SymbolMode, Footprint[fp].Type >= VER_MM); + GetTextLabelSize(PartData[fp], &LabelData[fp], SymbolMode, Footprint[fp].Type >= VER_MM); + if (SymbolMode) { + /* re-assign the pins to custom sections (now that the body size is known) */ + wxString templatename = GetTemplateName(PartData[fp]); + GetTemplateSections(templatename, CustomPinSections[fp], sizearray(CustomPinSections[fp])); + ReAssignPins(PinData[fp], PinDataCount[fp], BodySize[fp], CustomPinSections[fp], sizearray(CustomPinSections[fp])); + } + FieldEdited = false; + PartEdited = false; + PinNamesEdited = false; } void libmngrFrame::OnPasteGeneral(wxCommandEvent& event) { - if (SymbolMode) { - /* check that the pin list table has the focus */ - if (FindFocus() == m_gridPinNames->GetGridWindow()) { - OnPastePinList(event); - return; - } - } + if (SymbolMode) { + /* check that the pin list table has the focus */ + if (FindFocus() == m_gridPinNames->GetGridWindow()) { + OnPastePinList(event); + return; + } + } - /* if not handled, search on */ - event.Skip(); + /* if not handled, search on */ + event.Skip(); } void libmngrFrame::OnTextFieldChange(wxCommandEvent& event) { - wxTextCtrl* field = (wxTextCtrl*)event.GetEventObject(); - if (field->IsEditable()) - FieldEdited = true; - event.Skip(); + wxTextCtrl* field = (wxTextCtrl*)event.GetEventObject(); + if (field->IsEditable()) + FieldEdited = true; + event.Skip(); } void libmngrFrame::OnChoiceFieldChange(wxCommandEvent& event) { - FieldEdited = true; + FieldEdited = true; wxControl* ctrl = (wxControl*)event.GetEventObject(); wxWindowID id = ctrl->GetId(); if (id == m_choicePadShape->GetId()) - ChangePadInfo((wxControl*)m_choicePadShape); + ChangePadInfo((wxControl*)m_choicePadShape); else if (id == m_choiceShape->GetId()) - ChangeShape((wxControl*)m_choiceShape); - event.Skip(); + ChangeShape((wxControl*)m_choiceShape); + event.Skip(); } void libmngrFrame::OnEnterTextInfo(wxCommandEvent& event) { - ChangeTextInfo((wxControl*)event.GetEventObject()); + ChangeTextInfo((wxControl*)event.GetEventObject()); } void libmngrFrame::OnKillFocusTextInfo(wxFocusEvent& event) { - ChangeTextInfo((wxControl*)event.GetEventObject()); - event.Skip(); + ChangeTextInfo((wxControl*)event.GetEventObject()); + event.Skip(); } void libmngrFrame::ChangeTextInfo(wxControl* ctrl) { - if (FieldEdited) { - ctrl->SetBackgroundColour(CHANGED); - ctrl->Refresh(); - FieldEdited = false; - PartEdited = true; - m_btnSavePart->Enable(true); - m_btnRevertPart->Enable(true); - - /* adjust the footprint or symbol */ - wxASSERT(PartData[0].Count() > 0); - wxString field = m_txtDescription->GetValue(); - field = field.Trim(true); - field = field.Trim(false); - SetDescription(PartData[0], field, SymbolMode); - - field = m_txtAlias->GetValue(); - field = field.Trim(true); - field = field.Trim(false); - if (SymbolMode) - SetAliases(PartData[0], field); + if (FieldEdited) { + ctrl->SetBackgroundColour(CHANGED); + ctrl->Refresh(); + FieldEdited = false; + PartEdited = true; + m_btnSavePart->Enable(true); + m_btnRevertPart->Enable(true); + + /* adjust the footprint or symbol */ + wxASSERT(PartData[0].Count() > 0); + wxString field = m_txtDescription->GetValue(); + field = field.Trim(true); + field = field.Trim(false); + SetDescription(PartData[0], field, SymbolMode); + + field = m_txtAlias->GetValue(); + field = field.Trim(true); + field = field.Trim(false); + if (SymbolMode) + SetAliases(PartData[0], field); else - SetKeywords(PartData[0], field, SymbolMode); + SetKeywords(PartData[0], field, SymbolMode); if (SymbolMode) { - field = m_txtFootprintFilter->GetValue(); - field = field.Trim(true); - field = field.Trim(false); - SetFootprints(PartData[0], field); + field = m_txtFootprintFilter->GetValue(); + field = field.Trim(true); + field = field.Trim(false); + SetFootprints(PartData[0], field); } - } + } } static const wxString PinTypeNames[] = { wxT("input"), wxT("output"), wxT("bi-dir"), - wxT("tristate"), wxT("passive"), wxT("open-collector"), - wxT("open-emitter"), wxT("non-connect"), wxT("unspecified"), - wxT("power-in"), wxT("power-out") }; + wxT("tristate"), wxT("passive"), wxT("open-collector"), + wxT("open-emitter"), wxT("non-connect"), wxT("unspecified"), + wxT("power-in"), wxT("power-out") }; static const wxString PinShapeNames[] = { wxT("line"), wxT("inverted"), wxT("clock"), wxT("inv.clock"), wxT("*") }; static const wxString PinSectionNames[] = { wxT("left"), wxT("right"), wxT("top"), wxT("bottom") }; wxString libmngrFrame::GetPinSectionName(int side, int index) { - wxASSERT(side == 0 || side == 1); - wxASSERT(index >= 0 && index < PinInfo::SectionCount); - if (index < sizearray(PinSectionNames)) - return PinSectionNames[index]; + wxASSERT(side == 0 || side == 1); + wxASSERT(index >= 0 && index < PinInfo::SectionCount); + if (index < sizearray(PinSectionNames)) + return PinSectionNames[index]; - index -= sizearray(PinSectionNames); - if (CustomPinSections[side][index].IsValid()) - return CustomPinSections[side][index].Name(); - return wxEmptyString; + index -= sizearray(PinSectionNames); + if (CustomPinSections[side][index].IsValid()) + return CustomPinSections[side][index].Name(); + return wxEmptyString; } void libmngrFrame::OnPinNameChanged(wxGridEvent& event) { - static bool reenter = false; - if (!reenter) { - reenter = true; - m_gridPinNames->SetCellBackgroundColour(event.GetRow(), event.GetCol(), CHANGED); - #if 0 - m_gridPinNames->AutoSizeColumn(event.GetCol()); - #endif - PinNamesEdited = true; - PartEdited = true; - m_btnSavePart->Enable(true); - m_btnRevertPart->Enable(true); - - bool refreshtemplate = false; - - wxASSERT(m_gridPinNames->GetNumberRows() == PinDataCount[0]); /* pins cannot be added or removed in the table */ - for (int idx = 0; idx < m_gridPinNames->GetNumberRows(); idx++) { - PinData[0][idx].number = m_gridPinNames->GetCellValue(idx, 0); - wxString field = m_gridPinNames->GetCellValue(idx, 1); - field.Replace(wxT(" "), wxT("_")); - long part = 0; - if (field.Left(1).IsNumber() && field[1] == wxT(':')) { - field.Left(1).ToLong(&part); - field = field.Mid(2); - field.Trim(false); - } - PinData[0][idx].name = field; - - field = m_gridPinNames->GetCellValue(idx, 2); - for (int t = 0; t < sizearray(PinTypeNames); t++) - if (field.CmpNoCase(PinTypeNames[t]) == 0) - PinData[0][idx].type = t; - - field = m_gridPinNames->GetCellValue(idx, 3); - for (int s = 0; s < sizearray(PinShapeNames); s++) - if (field.CmpNoCase(PinShapeNames[s]) == 0) - PinData[0][idx].shape = s; - - field = m_gridPinNames->GetCellValue(idx, 4); - for (int s = 0; s < PinInfo::SectionCount; s++) { - wxString sectionname = GetPinSectionName(0, s); - if (field.CmpNoCase(sectionname) == 0) { - if (PinData[0][idx].section != s) { - refreshtemplate = true; - PinData[0][idx].section = s; - } - } - } - } - - SetPinNames(PartData[0], PinData[0], PinDataCount[0]); - if (refreshtemplate) - RebuildTemplate(); - m_panelView->Refresh(); - - reenter = false; - } - event.Skip(); + static bool reenter = false; + if (!reenter) { + reenter = true; + m_gridPinNames->SetCellBackgroundColour(event.GetRow(), event.GetCol(), CHANGED); + #if 0 + m_gridPinNames->AutoSizeColumn(event.GetCol()); + #endif + PinNamesEdited = true; + PartEdited = true; + m_btnSavePart->Enable(true); + m_btnRevertPart->Enable(true); + + bool refreshtemplate = false; + + wxASSERT(m_gridPinNames->GetNumberRows() == PinDataCount[0]); /* pins cannot be added or removed in the table */ + for (int idx = 0; idx < m_gridPinNames->GetNumberRows(); idx++) { + PinData[0][idx].number = m_gridPinNames->GetCellValue(idx, 0); + wxString field = m_gridPinNames->GetCellValue(idx, 1); + field.Replace(wxT(" "), wxT("_")); + long part = 0; + if (field.Left(1).IsNumber() && field[1] == wxT(':')) { + field.Left(1).ToLong(&part); + field = field.Mid(2); + field.Trim(false); + } + PinData[0][idx].name = field; + + field = m_gridPinNames->GetCellValue(idx, 2); + for (int t = 0; t < sizearray(PinTypeNames); t++) + if (field.CmpNoCase(PinTypeNames[t]) == 0) + PinData[0][idx].type = t; + + field = m_gridPinNames->GetCellValue(idx, 3); + for (int s = 0; s < sizearray(PinShapeNames); s++) + if (field.CmpNoCase(PinShapeNames[s]) == 0) + PinData[0][idx].shape = s; + + field = m_gridPinNames->GetCellValue(idx, 4); + for (int s = 0; s < PinInfo::SectionCount; s++) { + wxString sectionname = GetPinSectionName(0, s); + if (field.CmpNoCase(sectionname) == 0) { + if (PinData[0][idx].section != s) { + refreshtemplate = true; + PinData[0][idx].section = s; + } + } + } + } + + SetPinNames(PartData[0], PinData[0], PinDataCount[0]); + if (refreshtemplate) + RebuildTemplate(); + m_panelView->Refresh(); + + reenter = false; + } + event.Skip(); } void libmngrFrame::OnPinRightClick(wxGridEvent& event) { - wxASSERT((wxGrid*)event.GetEventObject() == m_gridPinNames); - if (CompareMode || PinDataCount[0] == 0) { - event.Skip(); - return; - } - - int row = event.GetRow(); - int col = event.GetCol(); - - /* only allow a popup menu when the column is read-write */ - if (m_gridPinNames->IsReadOnly(row, col)) { - event.Skip(); - return; - } - - /* make sure that the cell clicked on, is selected too (but also make sure - that cells in other columns are deselected) */ - bool addselection = true; - int total = 0; - for (int r = 0; r < m_gridPinNames->GetNumberRows() && addselection; r++) { - for (int c = 0; c < m_gridPinNames->GetNumberCols() && addselection; c++) { - if (m_gridPinNames->IsInSelection(r, c)) { - if (c == col) - total++; - else - addselection = false; - } - } - } - if (total == 0 || col <= 1) - addselection = false; - m_gridPinNames->SelectBlock(row, col, row, col, addselection); - - /* create a popup menu (depending on the column that was clicked) */ - wxString templatename = GetTemplateName(PartData[0]); - wxMenu *menuPopup = new wxMenu; - switch (col) { - case 0: /* pin */ - case 1: /* name */ - menuPopup->Append(IDM_SWAPABOVE, wxT("Move up"), wxT("Swap this pin with the one above")); - Connect(IDM_SWAPABOVE, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(libmngrFrame::OnSwapPins)); - menuPopup->Append(IDM_SWAPBELOW, wxT("Move down"), wxT("Swap this pin with the one below")); - Connect(IDM_SWAPBELOW, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(libmngrFrame::OnSwapPins)); - menuPopup->AppendSeparator(); - menuPopup->Append(IDM_PASTEPINLIST, wxT("Paste pin list"), wxT("Import a list of pin assignments from the clipboard")); - Connect(IDM_PASTEPINLIST, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(libmngrFrame::OnPastePinList)); - if (DontRebuildTemplate || templatename.length() == 0) { - menuPopup->Enable(IDM_SWAPABOVE, false); - menuPopup->Enable(IDM_SWAPBELOW, false); - } - break; - case 2: /* type */ - for (int i = 0; i < sizearray(PinTypeNames); i++) { - menuPopup->Append(IDM_PINTYPE + i, PinTypeNames[i]); - Connect(IDM_PINTYPE + i, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(libmngrFrame::OnSetPinType)); - } - break; - case 3: /* shape */ - for (int i = 0; i < sizearray(PinShapeNames) - 1; i++) { - menuPopup->Append(IDM_PINSHAPE + i, PinShapeNames[i]); - Connect(IDM_PINSHAPE + i, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(libmngrFrame::OnSetPinType)); - } - break; - case 4: /* position (section) */ - for (int i = 0; i < PinInfo::SectionCount; i++) { - wxString name = GetPinSectionName(0, i); - if (!name.IsEmpty()) { - menuPopup->Append(IDM_PINSECTION + i, name); - Connect(IDM_PINSECTION + i, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(libmngrFrame::OnSetPinType)); - } - } - break; - } - PopupMenu(menuPopup); + wxASSERT((wxGrid*)event.GetEventObject() == m_gridPinNames); + if (CompareMode || PinDataCount[0] == 0) { + event.Skip(); + return; + } + + int row = event.GetRow(); + int col = event.GetCol(); + + /* only allow a popup menu when the column is read-write */ + if (m_gridPinNames->IsReadOnly(row, col)) { + event.Skip(); + return; + } + + /* make sure that the cell clicked on, is selected too (but also make sure + that cells in other columns are deselected) */ + bool addselection = true; + int total = 0; + for (int r = 0; r < m_gridPinNames->GetNumberRows() && addselection; r++) { + for (int c = 0; c < m_gridPinNames->GetNumberCols() && addselection; c++) { + if (m_gridPinNames->IsInSelection(r, c)) { + if (c == col) + total++; + else + addselection = false; + } + } + } + if (total == 0 || col <= 1) + addselection = false; + m_gridPinNames->SelectBlock(row, col, row, col, addselection); + + /* create a popup menu (depending on the column that was clicked) */ + wxString templatename = GetTemplateName(PartData[0]); + wxMenu *menuPopup = new wxMenu; + switch (col) { + case 0: /* pin */ + case 1: /* name */ + menuPopup->Append(IDM_SWAPABOVE, wxT("Move up"), wxT("Swap this pin with the one above")); + Connect(IDM_SWAPABOVE, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(libmngrFrame::OnSwapPins)); + menuPopup->Append(IDM_SWAPBELOW, wxT("Move down"), wxT("Swap this pin with the one below")); + Connect(IDM_SWAPBELOW, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(libmngrFrame::OnSwapPins)); + menuPopup->AppendSeparator(); + menuPopup->Append(IDM_PASTEPINLIST, wxT("Paste pin list"), wxT("Import a list of pin assignments from the clipboard")); + Connect(IDM_PASTEPINLIST, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(libmngrFrame::OnPastePinList)); + if (DontRebuildTemplate || templatename.length() == 0) { + menuPopup->Enable(IDM_SWAPABOVE, false); + menuPopup->Enable(IDM_SWAPBELOW, false); + } + break; + case 2: /* type */ + for (int i = 0; i < sizearray(PinTypeNames); i++) { + menuPopup->Append(IDM_PINTYPE + i, PinTypeNames[i]); + Connect(IDM_PINTYPE + i, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(libmngrFrame::OnSetPinType)); + } + break; + case 3: /* shape */ + for (int i = 0; i < sizearray(PinShapeNames) - 1; i++) { + menuPopup->Append(IDM_PINSHAPE + i, PinShapeNames[i]); + Connect(IDM_PINSHAPE + i, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(libmngrFrame::OnSetPinType)); + } + break; + case 4: /* position (section) */ + for (int i = 0; i < PinInfo::SectionCount; i++) { + wxString name = GetPinSectionName(0, i); + if (!name.IsEmpty()) { + menuPopup->Append(IDM_PINSECTION + i, name); + Connect(IDM_PINSECTION + i, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(libmngrFrame::OnSetPinType)); + } + } + break; + } + PopupMenu(menuPopup); } bool libmngrFrame::RearrangePinNames(int direction) { - if (CompareMode || DontRebuildTemplate || PinDataCount[0] == 0) - return false; - wxString templatename = GetTemplateName(PartData[0]); - if (templatename.length() == 0) - return false; - - int col = m_gridPinNames->GetGridCursorCol(); - int row = m_gridPinNames->GetGridCursorRow(); - int total = m_gridPinNames->GetNumberRows(); - if ((direction > 0 && row >= total - 1) || (direction < 0 && row <= 0)) - return false; - - /* swap the rows, except the sequence numbers */ - int alt = (direction > 0) ? row + 1 : row - 1; - wxASSERT(alt >= 0 && alt < total); - wxASSERT(PartData[0].Count() > 0); - wxASSERT(row < PinDataCount[0] && alt < PinDataCount[0]); - int seq_row = PinData[0][row].seq; - int seq_alt = PinData[0][alt].seq; - PinInfo t = PinData[0][row]; - PinData[0][row] = PinData[0][alt]; - PinData[0][alt] = t; - PinData[0][row].seq = seq_row; - PinData[0][alt].seq = seq_alt; - - /* rebuild the template */ - RebuildTemplate(); - - /* refresh the data in the grid */ - wxString row_name = PinData[0][row].name; - if (PinData[0][row].part > 0) - row_name = wxString::Format(wxT("%d:"), PinData[0][row].part) + row_name; - wxString alt_name = PinData[0][alt].name; - if (PinData[0][alt].part > 0) - alt_name = wxString::Format(wxT("%d:"), PinData[0][alt].part) + alt_name; - m_gridPinNames->SetCellValue(row, 0, PinData[0][row].number); - m_gridPinNames->SetCellValue(row, 1, row_name); - m_gridPinNames->SetCellValue(row, 2, PinTypeNames[PinData[0][row].type]); - m_gridPinNames->SetCellValue(row, 3, PinShapeNames[PinData[0][row].shape]); - m_gridPinNames->SetCellValue(row, 4, GetPinSectionName(0, PinData[0][row].section)); - m_gridPinNames->SetCellValue(alt, 0, PinData[0][alt].number); - m_gridPinNames->SetCellValue(alt, 1, alt_name); - m_gridPinNames->SetCellValue(alt, 2, PinTypeNames[PinData[0][alt].type]); - m_gridPinNames->SetCellValue(alt, 3, PinShapeNames[PinData[0][alt].shape]); - m_gridPinNames->SetCellValue(alt, 4, GetPinSectionName(0, PinData[0][alt].section)); - - PartEdited = true; - m_btnSavePart->Enable(true); - m_btnRevertPart->Enable(true); - m_panelView->Refresh(); - - m_gridPinNames->SetGridCursor(alt, col); - return true; + if (CompareMode || DontRebuildTemplate || PinDataCount[0] == 0) + return false; + wxString templatename = GetTemplateName(PartData[0]); + if (templatename.length() == 0) + return false; + + int col = m_gridPinNames->GetGridCursorCol(); + int row = m_gridPinNames->GetGridCursorRow(); + int total = m_gridPinNames->GetNumberRows(); + if ((direction > 0 && row >= total - 1) || (direction < 0 && row <= 0)) + return false; + + /* swap the rows, except the sequence numbers */ + int alt = (direction > 0) ? row + 1 : row - 1; + wxASSERT(alt >= 0 && alt < total); + wxASSERT(PartData[0].Count() > 0); + wxASSERT(row < PinDataCount[0] && alt < PinDataCount[0]); + int seq_row = PinData[0][row].seq; + int seq_alt = PinData[0][alt].seq; + PinInfo t = PinData[0][row]; + PinData[0][row] = PinData[0][alt]; + PinData[0][alt] = t; + PinData[0][row].seq = seq_row; + PinData[0][alt].seq = seq_alt; + + /* rebuild the template */ + RebuildTemplate(); + + /* refresh the data in the grid */ + wxString row_name = PinData[0][row].name; + if (PinData[0][row].part > 0) + row_name = wxString::Format(wxT("%d:"), PinData[0][row].part) + row_name; + wxString alt_name = PinData[0][alt].name; + if (PinData[0][alt].part > 0) + alt_name = wxString::Format(wxT("%d:"), PinData[0][alt].part) + alt_name; + m_gridPinNames->SetCellValue(row, 0, PinData[0][row].number); + m_gridPinNames->SetCellValue(row, 1, row_name); + m_gridPinNames->SetCellValue(row, 2, PinTypeNames[PinData[0][row].type]); + m_gridPinNames->SetCellValue(row, 3, PinShapeNames[PinData[0][row].shape]); + m_gridPinNames->SetCellValue(row, 4, GetPinSectionName(0, PinData[0][row].section)); + m_gridPinNames->SetCellValue(alt, 0, PinData[0][alt].number); + m_gridPinNames->SetCellValue(alt, 1, alt_name); + m_gridPinNames->SetCellValue(alt, 2, PinTypeNames[PinData[0][alt].type]); + m_gridPinNames->SetCellValue(alt, 3, PinShapeNames[PinData[0][alt].shape]); + m_gridPinNames->SetCellValue(alt, 4, GetPinSectionName(0, PinData[0][alt].section)); + + PartEdited = true; + m_btnSavePart->Enable(true); + m_btnRevertPart->Enable(true); + m_panelView->Refresh(); + + m_gridPinNames->SetGridCursor(alt, col); + return true; } void libmngrFrame::OnPinNameRearrange(wxKeyEvent& event) { - if (event.m_altDown && (event.m_keyCode == WXK_DOWN || event.m_keyCode == WXK_UP)) - RearrangePinNames((event.m_keyCode == WXK_DOWN) ? 1 : -1); - else - event.Skip(); + if (event.m_altDown && (event.m_keyCode == WXK_DOWN || event.m_keyCode == WXK_UP)) + RearrangePinNames((event.m_keyCode == WXK_DOWN) ? 1 : -1); + else + event.Skip(); } void libmngrFrame::OnSwapPins(wxCommandEvent& event) { - RearrangePinNames((event.GetId() == IDM_SWAPBELOW) ? 1 : -1); + RearrangePinNames((event.GetId() == IDM_SWAPBELOW) ? 1 : -1); } void libmngrFrame::OnPastePinList(wxCommandEvent& /*event*/) { - if (!wxTheClipboard->Open()) - return; - if (!wxTheClipboard->IsSupported(wxDF_TEXT)) { - wxTheClipboard->Close(); - return; - } - - wxTextDataObject data; - wxTheClipboard->GetData(data); - wxTheClipboard->Close(); - wxArrayString lines = wxStringTokenize(data.GetText(), wxT("\r\n"), wxTOKEN_DEFAULT); - if (lines.Count() == 0) - return; - - /* determine separator: tab, comma, semicolon, space */ - bool allow_tab = true, allow_comma = true, allow_semi = true, allow_space = true; - wxRegEx flt(wxT("[^\\w][1-9]\\d*[^\\w]"), wxRE_ADVANCED); - wxASSERT(flt.IsValid()); - for (unsigned idx = 0; idx < lines.Count(); idx++) { - wxString line = lines[idx]; - /* check whether there is a number delimited by whitespace or punctuation */ - if (!flt.Matches(line)) - continue; - if (allow_tab && line.Find(wxT('\t')) < 0) - allow_tab = false; - if (allow_comma && line.Find(wxT(',')) < 0) - allow_comma = false; - if (allow_semi && line.Find(wxT(';')) < 0) - allow_semi = false; - if (allow_space && line.Find(wxT(' ')) < 0) - allow_space = false; - } - wxChar separator = wxT('\0'); - if (allow_tab) - separator = wxT('\t'); - else if (allow_comma) - separator = wxT(','); - else if (allow_semi) - separator = wxT(';'); - else if (allow_space) - separator = wxT(' '); - else - return; - - wxStringTokenizerMode mode = (separator == wxT(' ')) ? wxTOKEN_DEFAULT : wxTOKEN_RET_EMPTY_ALL; - - /* determine where the pin number is (first or last) */ - wxString line = lines[0]; //??? should check whether this is a line that matches the regular expression for valid text lines - bool pinfirst = false; - bool pinlast = false; - wxArrayString tokens = wxStringTokenize(line, separator, mode); - if (tokens.Count() < 2) - return; - long pinnr; - wxString field = tokens[0]; - if (field.Right(1) == wxT(",")) - field = field.Left(field.Length() - 1); - if (field.ToLong(&pinnr) && pinnr > 0) - pinfirst = true; - field = tokens[tokens.Count() - 1]; - if (field.ToLong(&pinnr) && pinnr > 0) - pinlast = true; - if ((pinfirst && pinlast) || (!pinfirst && !pinlast)) - return; /* pin number location could not be determined */ - - /* check which column to use for the name */ - unsigned name_col; - if (pinlast) { - name_col = 0; /* when the pin number is in the last column, assume the names to be in the first */ - } else { - wxASSERT(pinfirst); - name_col = 1; /* assume that the name follows the number */ - } - - /* run over the clipboard data */ - wxString field_raw; - for (unsigned idx = 0; idx < lines.Count(); idx++) { - line = lines[idx]; - wxArrayString tokens = wxStringTokenize(line, separator, mode); - if (tokens.Count() >= 2) { - if (pinlast) - field_raw = tokens[tokens.Count() - 1]; - else - field_raw = tokens[0]; - if (field_raw.Right(1) == wxT(",")) - field = field_raw.Left(field_raw.Length() - 1); - else - field = field_raw; - if (field.ToLong(&pinnr) && pinnr > 0) { - /* see whether multiple pin numbers are on the same line */ - wxArrayLong pins; - pins.Add(pinnr); - unsigned col = name_col; - if (pinfirst && field_raw.Right(1) == wxT(",")) { - for (col = 1; col < tokens.Count() - 1; col++) { - field_raw = tokens[col]; - if (field_raw.Right(1) == wxT(",")) - field = field_raw.Left(field_raw.Length() - 1); - else - field = field_raw; - if (!field.ToLong(&pinnr) || pinnr <= 0) - break; - pins.Add(pinnr); - if (field_raw.Right(1) != wxT(",")) - break; - } - if (col < tokens.Count() - 1) - col += 1; /* skip last column with pin number */ - } - for (unsigned pinidx = 0; pinidx < pins.Count(); pinidx++) { - pinnr = pins[pinidx]; - /* find the pin number in the grid */ - int row, emptyrow = -1; - for (row = 0; row < m_gridPinNames->GetNumberRows(); row++) { - wxString pinname = m_gridPinNames->GetCellValue(row, 0); - long p; - if (pinname.ToLong(&p) && p == pinnr) - break; /* found */ - if (emptyrow < 0 && pinname.length() == 0) - emptyrow = row; /* keep reference to first row without a pin number */ - } - /* if not found, use the first empty spot in the grid */ - if (row >= m_gridPinNames->GetNumberRows() && emptyrow >= 0) { - row = emptyrow; - wxString pinname = wxString::Format(wxT("%d"), pinnr); - m_gridPinNames->SetCellValue(row, 0, pinname); - } - if (row < m_gridPinNames->GetNumberRows()) { - field = tokens[col]; - if (field.CmpNoCase(wxT("V")) == 0 && (col + 1) < tokens.Count()) - field += tokens[col + 1]; /* convert "V SS" to "VSS" */ - m_gridPinNames->SetCellValue(row, 1, field); - /* check the other columns for keywords line "input" and "output" */ - wxString type_name; - if (field.CmpNoCase(wxT("VCC")) == 0 || field.CmpNoCase(wxT("VDD")) == 0) - type_name = wxT("power_in"); - else if (field.CmpNoCase(wxT("N.C.")) == 0 || field.CmpNoCase(wxT("N/C")) == 0 || field.CmpNoCase(wxT("NC")) == 0) - type_name = wxT("power_in"); - for (unsigned c = col + 1; c < tokens.Count() && type_name.Length() == 0; c++) { - field = tokens[c]; - field.MakeUpper(); - if (field.Find(wxT("POWER")) >= 0 || field.Find(wxT("PWR")) >= 0) - type_name = wxT("power-in"); - else if (field.Cmp(wxT("IN")) == 0 || field.Cmp(wxT("INPUT")) == 0 || field.Find(wxT("_IN")) >= 0) - type_name = wxT("input"); - else if (field.Cmp(wxT("OUT")) == 0 || field.Cmp(wxT("OUTPUT")) == 0 || field.Find(wxT("_OUT")) >= 0) - type_name = wxT("output"); - else if (field.Cmp(wxT("I/O")) == 0 || field.Find(wxT("_IO")) >= 0) - type_name = wxT("bi-dir"); - else if (field.Cmp(wxT("N.C.")) == 0 || field.Cmp(wxT("N/C")) == 0 || field.Cmp(wxT("NC")) == 0) - type_name = wxT("non-connect"); - } - if (type_name.Length() > 0) - m_gridPinNames->SetCellValue(row, 2, type_name); - } - } - } - } - } + if (!wxTheClipboard->Open()) + return; + if (!wxTheClipboard->IsSupported(wxDF_TEXT)) { + wxTheClipboard->Close(); + return; + } + + wxTextDataObject data; + wxTheClipboard->GetData(data); + wxTheClipboard->Close(); + wxArrayString lines = wxStringTokenize(data.GetText(), wxT("\r\n"), wxTOKEN_DEFAULT); + if (lines.Count() == 0) + return; + + /* determine separator: tab, comma, semicolon, space */ + bool allow_tab = true, allow_comma = true, allow_semi = true, allow_space = true; + wxRegEx flt(wxT("[^\\w][1-9]\\d*[^\\w]"), wxRE_ADVANCED); + wxASSERT(flt.IsValid()); + for (unsigned idx = 0; idx < lines.Count(); idx++) { + wxString line = lines[idx]; + /* check whether there is a number delimited by whitespace or punctuation */ + if (!flt.Matches(line)) + continue; + if (allow_tab && line.Find(wxT('\t')) < 0) + allow_tab = false; + if (allow_comma && line.Find(wxT(',')) < 0) + allow_comma = false; + if (allow_semi && line.Find(wxT(';')) < 0) + allow_semi = false; + if (allow_space && line.Find(wxT(' ')) < 0) + allow_space = false; + } + wxChar separator = wxT('\0'); + if (allow_tab) + separator = wxT('\t'); + else if (allow_comma) + separator = wxT(','); + else if (allow_semi) + separator = wxT(';'); + else if (allow_space) + separator = wxT(' '); + else + return; + + wxStringTokenizerMode mode = (separator == wxT(' ')) ? wxTOKEN_DEFAULT : wxTOKEN_RET_EMPTY_ALL; + + /* determine where the pin number is (first or last) */ + wxString line = lines[0]; //??? should check whether this is a line that matches the regular expression for valid text lines + bool pinfirst = false; + bool pinlast = false; + wxArrayString tokens = wxStringTokenize(line, separator, mode); + if (tokens.Count() < 2) + return; + long pinnr; + wxString field = tokens[0]; + if (field.Right(1) == wxT(",")) + field = field.Left(field.Length() - 1); + if (field.ToLong(&pinnr) && pinnr > 0) + pinfirst = true; + field = tokens[tokens.Count() - 1]; + if (field.ToLong(&pinnr) && pinnr > 0) + pinlast = true; + if ((pinfirst && pinlast) || (!pinfirst && !pinlast)) + return; /* pin number location could not be determined */ + + /* check which column to use for the name */ + unsigned name_col; + if (pinlast) { + name_col = 0; /* when the pin number is in the last column, assume the names to be in the first */ + } else { + wxASSERT(pinfirst); + name_col = 1; /* assume that the name follows the number */ + } + + /* run over the clipboard data */ + wxString field_raw; + for (unsigned idx = 0; idx < lines.Count(); idx++) { + line = lines[idx]; + wxArrayString tokens = wxStringTokenize(line, separator, mode); + if (tokens.Count() >= 2) { + if (pinlast) + field_raw = tokens[tokens.Count() - 1]; + else + field_raw = tokens[0]; + if (field_raw.Right(1) == wxT(",")) + field = field_raw.Left(field_raw.Length() - 1); + else + field = field_raw; + if (field.ToLong(&pinnr) && pinnr > 0) { + /* see whether multiple pin numbers are on the same line */ + wxArrayLong pins; + pins.Add(pinnr); + unsigned col = name_col; + if (pinfirst && field_raw.Right(1) == wxT(",")) { + for (col = 1; col < tokens.Count() - 1; col++) { + field_raw = tokens[col]; + if (field_raw.Right(1) == wxT(",")) + field = field_raw.Left(field_raw.Length() - 1); + else + field = field_raw; + if (!field.ToLong(&pinnr) || pinnr <= 0) + break; + pins.Add(pinnr); + if (field_raw.Right(1) != wxT(",")) + break; + } + if (col < tokens.Count() - 1) + col += 1; /* skip last column with pin number */ + } + for (unsigned pinidx = 0; pinidx < pins.Count(); pinidx++) { + pinnr = pins[pinidx]; + /* find the pin number in the grid */ + int row, emptyrow = -1; + for (row = 0; row < m_gridPinNames->GetNumberRows(); row++) { + wxString pinname = m_gridPinNames->GetCellValue(row, 0); + long p; + if (pinname.ToLong(&p) && p == pinnr) + break; /* found */ + if (emptyrow < 0 && pinname.length() == 0) + emptyrow = row; /* keep reference to first row without a pin number */ + } + /* if not found, use the first empty spot in the grid */ + if (row >= m_gridPinNames->GetNumberRows() && emptyrow >= 0) { + row = emptyrow; + wxString pinname = wxString::Format(wxT("%d"), pinnr); + m_gridPinNames->SetCellValue(row, 0, pinname); + } + if (row < m_gridPinNames->GetNumberRows()) { + field = tokens[col]; + if (field.CmpNoCase(wxT("V")) == 0 && (col + 1) < tokens.Count()) + field += tokens[col + 1]; /* convert "V SS" to "VSS" */ + m_gridPinNames->SetCellValue(row, 1, field); + /* check the other columns for keywords line "input" and "output" */ + wxString type_name; + if (field.CmpNoCase(wxT("VCC")) == 0 || field.CmpNoCase(wxT("VDD")) == 0) + type_name = wxT("power_in"); + else if (field.CmpNoCase(wxT("N.C.")) == 0 || field.CmpNoCase(wxT("N/C")) == 0 || field.CmpNoCase(wxT("NC")) == 0) + type_name = wxT("power_in"); + for (unsigned c = col + 1; c < tokens.Count() && type_name.Length() == 0; c++) { + field = tokens[c]; + field.MakeUpper(); + if (field.Find(wxT("POWER")) >= 0 || field.Find(wxT("PWR")) >= 0) + type_name = wxT("power-in"); + else if (field.Cmp(wxT("IN")) == 0 || field.Cmp(wxT("INPUT")) == 0 || field.Find(wxT("_IN")) >= 0) + type_name = wxT("input"); + else if (field.Cmp(wxT("OUT")) == 0 || field.Cmp(wxT("OUTPUT")) == 0 || field.Find(wxT("_OUT")) >= 0) + type_name = wxT("output"); + else if (field.Cmp(wxT("I/O")) == 0 || field.Find(wxT("_IO")) >= 0) + type_name = wxT("bi-dir"); + else if (field.Cmp(wxT("N.C.")) == 0 || field.Cmp(wxT("N/C")) == 0 || field.Cmp(wxT("NC")) == 0) + type_name = wxT("non-connect"); + } + if (type_name.Length() > 0) + m_gridPinNames->SetCellValue(row, 2, type_name); + } + } + } + } + } } void libmngrFrame::OnSetPinType(wxCommandEvent& event) { - /* get the string to store */ - wxString field; - int id = event.GetId(); - if (id >= IDM_PINTYPE && id < IDM_PINSHAPE) - field = PinTypeNames[id - IDM_PINTYPE]; - else if (id >= IDM_PINSHAPE && id < IDM_PINSECTION) - field = PinShapeNames[id - IDM_PINSHAPE]; - else - field = GetPinSectionName(0, id - IDM_PINSECTION); - - /* check which column has the selections (with wxWidgets, getting the - list of selected cells is complicated, but since our grids are small, - we run over the entire grid until the first selected cell is found */ - int col = -1; - for (int r = 0; r < m_gridPinNames->GetNumberRows() && col < 0; r++) - for (int c = 0; c < m_gridPinNames->GetNumberCols() && col < 0; c++) - if (m_gridPinNames->IsInSelection(r, c)) - col = c; - - /* get array index of the selected string */ - int fieldidx = -1; - switch (col) { - case 2: - for (int i = 0; i < sizearray(PinTypeNames) && fieldidx < 0; i++) - if (field.CmpNoCase(PinTypeNames[i]) == 0) - fieldidx = i; - break; - case 3: - for (int i = 0; i < sizearray(PinShapeNames) && fieldidx < 0; i++) - if (field.CmpNoCase(PinShapeNames[i]) == 0) - fieldidx = i; - break; - case 4: - for (int i = 0; i < PinInfo::SectionCount && fieldidx < 0; i++) { - wxString sectionname = GetPinSectionName(0, i); - if (field.CmpNoCase(sectionname) == 0) - fieldidx = i; - } - break; - default: - wxASSERT(0); - } - wxASSERT(fieldidx >= 0); - - /* run over the column and act on selected items */ - for (int r = 0; r < m_gridPinNames->GetNumberRows(); r++) { - if (m_gridPinNames->IsInSelection(r, col)) { - m_gridPinNames->SetCellValue(r, col, field); - m_gridPinNames->SetCellBackgroundColour(r, col, CHANGED); - /* adjust in the structure too */ - switch (col) { - case 2: - PinData[0][r].type = fieldidx; - break; - case 3: - PinData[0][r].shape = fieldidx; - break; - case 4: - PinData[0][r].section = fieldidx; - break; - } - } - } - - #if 0 - m_gridPinNames->AutoSizeColumn(col); - #endif - - PinNamesEdited = true; - PartEdited = true; - m_btnSavePart->Enable(true); - m_btnRevertPart->Enable(true); - - SetPinNames(PartData[0], PinData[0], PinDataCount[0]); - if (col == 4) - RebuildTemplate(); - m_panelView->Refresh(); + /* get the string to store */ + wxString field; + int id = event.GetId(); + if (id >= IDM_PINTYPE && id < IDM_PINSHAPE) + field = PinTypeNames[id - IDM_PINTYPE]; + else if (id >= IDM_PINSHAPE && id < IDM_PINSECTION) + field = PinShapeNames[id - IDM_PINSHAPE]; + else + field = GetPinSectionName(0, id - IDM_PINSECTION); + + /* check which column has the selections (with wxWidgets, getting the + list of selected cells is complicated, but since our grids are small, + we run over the entire grid until the first selected cell is found */ + int col = -1; + for (int r = 0; r < m_gridPinNames->GetNumberRows() && col < 0; r++) + for (int c = 0; c < m_gridPinNames->GetNumberCols() && col < 0; c++) + if (m_gridPinNames->IsInSelection(r, c)) + col = c; + + /* get array index of the selected string */ + int fieldidx = -1; + switch (col) { + case 2: + for (int i = 0; i < sizearray(PinTypeNames) && fieldidx < 0; i++) + if (field.CmpNoCase(PinTypeNames[i]) == 0) + fieldidx = i; + break; + case 3: + for (int i = 0; i < sizearray(PinShapeNames) && fieldidx < 0; i++) + if (field.CmpNoCase(PinShapeNames[i]) == 0) + fieldidx = i; + break; + case 4: + for (int i = 0; i < PinInfo::SectionCount && fieldidx < 0; i++) { + wxString sectionname = GetPinSectionName(0, i); + if (field.CmpNoCase(sectionname) == 0) + fieldidx = i; + } + break; + default: + wxASSERT(0); + } + wxASSERT(fieldidx >= 0); + + /* run over the column and act on selected items */ + for (int r = 0; r < m_gridPinNames->GetNumberRows(); r++) { + if (m_gridPinNames->IsInSelection(r, col)) { + m_gridPinNames->SetCellValue(r, col, field); + m_gridPinNames->SetCellBackgroundColour(r, col, CHANGED); + /* adjust in the structure too */ + switch (col) { + case 2: + PinData[0][r].type = fieldidx; + break; + case 3: + PinData[0][r].shape = fieldidx; + break; + case 4: + PinData[0][r].section = fieldidx; + break; + } + } + } + + #if 0 + m_gridPinNames->AutoSizeColumn(col); + #endif + + PinNamesEdited = true; + PartEdited = true; + m_btnSavePart->Enable(true); + m_btnRevertPart->Enable(true); + + SetPinNames(PartData[0], PinData[0], PinDataCount[0]); + if (col == 4) + RebuildTemplate(); + m_panelView->Refresh(); } void libmngrFrame::OnEnterPadCount(wxCommandEvent& event) { - ChangePadCount((wxControl*)event.GetEventObject()); + ChangePadCount((wxControl*)event.GetEventObject()); } void libmngrFrame::OnKillFocusPadCount(wxFocusEvent& event) { - ChangePadCount((wxControl*)event.GetEventObject()); - event.Skip(); + ChangePadCount((wxControl*)event.GetEventObject()); + event.Skip(); } void libmngrFrame::ChangePadCount(wxControl* ctrl) { - if (FieldEdited) { - ctrl->SetBackgroundColour(CHANGED); - ctrl->Refresh(); - FieldEdited = false; - PartEdited = true; - m_btnSavePart->Enable(true); - m_btnRevertPart->Enable(true); - - /* check whether the pin count is valid */ - wxString field = m_txtPadCount->GetValue(); - long pins; - field.ToLong(&pins); - if (pins < 0) - return; - - wxASSERT(PartData[0].Count() > 0); - wxString templatename = GetTemplateName(PartData[0]); - wxASSERT(templatename.length() > 0); /* if there is no template, the field for - the number of pins is read-only */ - if (templatename.length() == 0) - return; - bool valid = ValidPinCount(pins, templatename, SymbolMode); - if (!valid) { - wxString msg = wxT("The template ") + templatename + wxString::Format(wxT(" does not allow a pin count of %d."), pins); - /* get the notes for the template and add these to the error message */ - wxString note = GetTemplateHeaderField(templatename, wxT("pins"), SymbolMode); - if (note.length() > 0) - msg += wxT("\n\nNote: pin specification = ") + note; - wxMessageBox(msg); - return; - } - - /* first, set all variables to the defaults of the template */ - wxString leftmod = GetSelection(m_listModulesLeft); - wxString rightmod = GetSelection(m_listModulesRight); - wxASSERT(leftmod.IsEmpty() || rightmod.IsEmpty()); - wxString footprintname = (leftmod.length() > 0) ? leftmod : rightmod; - wxString description = m_txtDescription->GetValue(); + if (FieldEdited) { + ctrl->SetBackgroundColour(CHANGED); + ctrl->Refresh(); + FieldEdited = false; + PartEdited = true; + m_btnSavePart->Enable(true); + m_btnRevertPart->Enable(true); + + /* check whether the pin count is valid */ + wxString field = m_txtPadCount->GetValue(); + long pins; + field.ToLong(&pins); + if (pins < 0) + return; + + wxASSERT(PartData[0].Count() > 0); + wxString templatename = GetTemplateName(PartData[0]); + wxASSERT(templatename.length() > 0); /* if there is no template, the field for + the number of pins is read-only */ + if (templatename.length() == 0) + return; + bool valid = ValidPinCount(pins, templatename, SymbolMode); + if (!valid) { + wxString msg = wxT("The template ") + templatename + wxString::Format(wxT(" does not allow a pin count of %d."), pins); + /* get the notes for the template and add these to the error message */ + wxString note = GetTemplateHeaderField(templatename, wxT("pins"), SymbolMode); + if (note.length() > 0) + msg += wxT("\n\nNote: pin specification = ") + note; + wxMessageBox(msg); + return; + } + + /* first, set all variables to the defaults of the template */ + wxString leftmod = GetSelection(m_listModulesLeft); + wxString rightmod = GetSelection(m_listModulesRight); + wxASSERT(leftmod.IsEmpty() || rightmod.IsEmpty()); + wxString footprintname = (leftmod.length() > 0) ? leftmod : rightmod; + wxString description = m_txtDescription->GetValue(); wxString tags = m_txtAlias->GetValue(); - wxString prefix = wxEmptyString; - if (SymbolMode) - prefix = GetPrefix(PartData[0]); - RPNexpression rpn; - rpn.SetVariable(RPNvariable("PT", pins)); /* other defaults may depend on the correct pin count */ - SetVarDefaults(&rpn, templatename, footprintname, description, prefix, tags, true); - /* then, update the variables from the fields */ - SetVarsFromFields(&rpn, SymbolMode); - SetVarsFromTemplate(&rpn, templatename, SymbolMode); - - /* refresh the footprint or symbol from the template (completely) */ - wxArrayString templatemodule; - LoadTemplate(templatename, &templatemodule, SymbolMode); - if (SymbolMode) { - if (pins == 0) - return; - /* first rebuild the pininfo structure */ - PinInfo* info = new PinInfo[pins]; - if (info == NULL) - return; - int totals[PinInfo::SectionCount]; - int counts[PinInfo::SectionCount]; - for (int s = 0; s < PinInfo::SectionCount; s++) { - totals[s] = 0; - counts[s] = 0; - char str[20]; - sprintf(str, "PT:%d", s); - rpn.Set(str); - if (rpn.Parse() == RPN_OK) { - RPNvalue v = rpn.Value(); - totals[s] = (int)(v.Double() + 0.001); - } - } - /* copy the existing pins (but only if they have a label) */ - for (int i = 0; i < pins; i++) { - info[i].section = -1; - if (i < PinDataCount[0] - && (PinData[0][i].name.Cmp(wxT("~")) != 0 - || PinData[0][i].type != PinInfo::Passive - || PinData[0][i].shape != PinInfo::Line)) - { - info[i] = PinData[0][i]; - int s = info[i].section; - counts[s] += 1; - } - } - /* complete with the new pins */ - int cursec = PinInfo::Left; - for (int i = 0; i < pins; i++) { - while (cursec < PinInfo::SectionCount && counts[cursec] >= totals[cursec]) - cursec++; - if (cursec >= PinInfo::SectionCount) - cursec = PinInfo::Left; /* on error, map remaining pins to left side */ - info[i].seq = i; - if (info[i].section == -1) { - info[i].number = wxString::Format(wxT("%d"), i + 1); - info[i].name = wxT("~"); - info[i].type = PinInfo::Passive; - info[i].shape = PinInfo::Line; - info[i].section = cursec; - info[i].part = 0; - counts[cursec] += 1; - } - } - /* save the current aliases and footprint list, because these are absent from the templates */ - wxString aliases = GetAliases(PartData[0]); - wxString footprints = GetFootprints(PartData[0]); - /* create a symbol from the template, then restore the aliases and footprints */ - SymbolFromTemplate(&PartData[0], templatemodule, rpn, info, pins); - if (aliases.Length() > 0) - SetAliases(PartData[0], aliases); - if (footprints.Length() > 0) - SetFootprints(PartData[0], footprints); - /* now swap the PinInfo in the symbol data structure */ - delete[] PinData[0]; - PinDataCount[0] = pins; - PinData[0] = info; - GetPinNames(PartData[0], PinData[0], NULL); /* reload pins, for updated information */ - /* grid must be refreshed / resized */ - int currows = m_gridPinNames->GetNumberRows(); - if (pins < currows) { - m_gridPinNames->DeleteRows(pins, currows - pins); - } else { - m_gridPinNames->InsertRows(currows, pins - currows); - m_gridPinNames->EnableEditing(true); - for (int idx = currows; idx < pins; idx++) { - wxString field = PinData[0][idx].name; - if (PinData[0][idx].part > 0) - field = wxString::Format(wxT("%d:"), PinData[0][idx].part) + field; - m_gridPinNames->SetCellValue((int)idx, 0, PinData[0][idx].number); - m_gridPinNames->SetCellValue((int)idx, 1, field); - m_gridPinNames->SetCellValue((int)idx, 2, PinTypeNames[PinData[0][idx].type]); - m_gridPinNames->SetCellValue((int)idx, 3, PinShapeNames[PinData[0][idx].shape]); - m_gridPinNames->SetCellValue((int)idx, 4, GetPinSectionName(0, PinData[0][idx].section)); - /* no cell needs to be set to read-only and no new cell needs to be coloured */ - m_gridPinNames->SetCellEditor(idx, 2, new wxGridCellChoiceEditor(sizearray(PinTypeNames), PinTypeNames)); - m_gridPinNames->SetCellEditor(idx, 3, new wxGridCellChoiceEditor(sizearray(PinShapeNames) - 1, PinShapeNames)); - wxArrayString list; - for (int i = 0; i < PinInfo::SectionCount; i++) { - wxString name = GetPinSectionName(0, i); - if (name.Length() > 0) - list.Add(name); - } - m_gridPinNames->SetCellEditor(idx, 4, new wxGridCellChoiceEditor(list)); - } - } - /* existing pins may have been implicitly assigned to a different section; - update all rows of the fields */ - for (int idx = 0; idx < pins; idx++) - m_gridPinNames->SetCellValue((int)idx, 4, GetPinSectionName(0, PinData[0][idx].section)); - } else { - FootprintFromTemplate(&PartData[0], templatemodule, rpn, false); - Footprint[0].Type = VER_MM; /* should already be set to this */ - TranslatePadInfo(&PartData[0], &Footprint[0]); + wxString prefix = wxEmptyString; + if (SymbolMode) + prefix = GetPrefix(PartData[0]); + RPNexpression rpn; + rpn.SetVariable(RPNvariable("PT", pins)); /* other defaults may depend on the correct pin count */ + SetVarDefaults(&rpn, templatename, footprintname, description, prefix, tags, true); + /* then, update the variables from the fields */ + SetVarsFromFields(&rpn, SymbolMode); + SetVarsFromTemplate(&rpn, templatename, SymbolMode); + + /* refresh the footprint or symbol from the template (completely) */ + wxArrayString templatemodule; + LoadTemplate(templatename, &templatemodule, SymbolMode); + if (SymbolMode) { + if (pins == 0) + return; + /* first rebuild the pininfo structure */ + PinInfo* info = new PinInfo[pins]; + if (info == NULL) + return; + int totals[PinInfo::SectionCount]; + int counts[PinInfo::SectionCount]; + for (int s = 0; s < PinInfo::SectionCount; s++) { + totals[s] = 0; + counts[s] = 0; + char str[20]; + sprintf(str, "PT:%d", s); + rpn.Set(str); + if (rpn.Parse() == RPN_OK) { + RPNvalue v = rpn.Value(); + totals[s] = (int)(v.Double() + 0.001); + } + } + /* copy the existing pins (but only if they have a label) */ + for (int i = 0; i < pins; i++) { + info[i].section = -1; + if (i < PinDataCount[0] + && (PinData[0][i].name.Cmp(wxT("~")) != 0 + || PinData[0][i].type != PinInfo::Passive + || PinData[0][i].shape != PinInfo::Line)) + { + info[i] = PinData[0][i]; + int s = info[i].section; + counts[s] += 1; + } + } + /* complete with the new pins */ + int cursec = PinInfo::Left; + for (int i = 0; i < pins; i++) { + while (cursec < PinInfo::SectionCount && counts[cursec] >= totals[cursec]) + cursec++; + if (cursec >= PinInfo::SectionCount) + cursec = PinInfo::Left; /* on error, map remaining pins to left side */ + info[i].seq = i; + if (info[i].section == -1) { + info[i].number = wxString::Format(wxT("%d"), i + 1); + info[i].name = wxT("~"); + info[i].type = PinInfo::Passive; + info[i].shape = PinInfo::Line; + info[i].section = cursec; + info[i].part = 0; + counts[cursec] += 1; + } + } + /* save the current aliases and footprint list, because these are absent from the templates */ + wxString aliases = GetAliases(PartData[0]); + wxString footprints = GetFootprints(PartData[0]); + /* create a symbol from the template, then restore the aliases and footprints */ + SymbolFromTemplate(&PartData[0], templatemodule, rpn, info, pins); + if (aliases.Length() > 0) + SetAliases(PartData[0], aliases); + if (footprints.Length() > 0) + SetFootprints(PartData[0], footprints); + /* now swap the PinInfo in the symbol data structure */ + delete[] PinData[0]; + PinDataCount[0] = pins; + PinData[0] = info; + GetPinNames(PartData[0], PinData[0], NULL); /* reload pins, for updated information */ + /* grid must be refreshed / resized */ + int currows = m_gridPinNames->GetNumberRows(); + if (pins < currows) { + m_gridPinNames->DeleteRows(pins, currows - pins); + } else { + m_gridPinNames->InsertRows(currows, pins - currows); + m_gridPinNames->EnableEditing(true); + for (int idx = currows; idx < pins; idx++) { + wxString field = PinData[0][idx].name; + if (PinData[0][idx].part > 0) + field = wxString::Format(wxT("%d:"), PinData[0][idx].part) + field; + m_gridPinNames->SetCellValue((int)idx, 0, PinData[0][idx].number); + m_gridPinNames->SetCellValue((int)idx, 1, field); + m_gridPinNames->SetCellValue((int)idx, 2, PinTypeNames[PinData[0][idx].type]); + m_gridPinNames->SetCellValue((int)idx, 3, PinShapeNames[PinData[0][idx].shape]); + m_gridPinNames->SetCellValue((int)idx, 4, GetPinSectionName(0, PinData[0][idx].section)); + /* no cell needs to be set to read-only and no new cell needs to be coloured */ + m_gridPinNames->SetCellEditor(idx, 2, new wxGridCellChoiceEditor(sizearray(PinTypeNames), PinTypeNames)); + m_gridPinNames->SetCellEditor(idx, 3, new wxGridCellChoiceEditor(sizearray(PinShapeNames) - 1, PinShapeNames)); + wxArrayString list; + for (int i = 0; i < PinInfo::SectionCount; i++) { + wxString name = GetPinSectionName(0, i); + if (name.Length() > 0) + list.Add(name); + } + m_gridPinNames->SetCellEditor(idx, 4, new wxGridCellChoiceEditor(list)); + } + } + /* existing pins may have been implicitly assigned to a different section; + update all rows of the fields */ + for (int idx = 0; idx < pins; idx++) + m_gridPinNames->SetCellValue((int)idx, 4, GetPinSectionName(0, PinData[0][idx].section)); + } else { + FootprintFromTemplate(&PartData[0], templatemodule, rpn, false); + Footprint[0].Type = VER_MM; /* should already be set to this */ + TranslatePadInfo(&PartData[0], &Footprint[0]); Update3DModel(PartData[0]); - } - m_panelView->Refresh(); - } + } + m_panelView->Refresh(); + } } void libmngrFrame::OnEnterPadInfo(wxCommandEvent& event) { - ChangePadInfo((wxControl*)event.GetEventObject()); + ChangePadInfo((wxControl*)event.GetEventObject()); } void libmngrFrame::OnKillFocusPadInfo(wxFocusEvent& event) { - ChangePadInfo((wxControl*)event.GetEventObject()); - event.Skip(); + ChangePadInfo((wxControl*)event.GetEventObject()); + event.Skip(); } void libmngrFrame::ChangePadInfo(wxControl* ctrl) { - if (FieldEdited) { - ctrl->SetBackgroundColour(CHANGED); - ctrl->Refresh(); - FieldEdited = false; - PartEdited = true; - m_btnSavePart->Enable(true); - m_btnRevertPart->Enable(true); - - /* adjust the footprint */ - wxASSERT(PartData[0].Count() > 0); - FootprintInfo adjusted = Footprint[0]; - long idx; - wxString field; - - idx = m_choicePadShape->GetSelection(); - if (idx >= 0) - field = m_choicePadShape->GetString(idx); - if (field.CmpNoCase(wxT("Round")) == 0) - adjusted.PadShape = 'C'; - else if (field.CmpNoCase(wxT("Obround")) == 0) - adjusted.PadShape = 'O'; - else if (field.CmpNoCase(wxT("Rectangular")) == 0) - adjusted.PadShape = 'R'; - else if (field.CmpNoCase(wxT("Round + square")) == 0) - adjusted.PadShape = 'S'; - else if (field.CmpNoCase(wxT("Trapezoid")) == 0) - adjusted.PadShape = 'T'; - - /* for circular and square+round pads, the width & length should be the same */ - if (adjusted.PadShape == 'C' || adjusted.PadShape == 'S') { - if (ctrl == m_txtPadWidth) - m_txtPadLength->SetValue(m_txtPadWidth->GetValue()); - else if (ctrl == m_txtPadLength) - m_txtPadWidth->SetValue(m_txtPadLength->GetValue()); - } - - double dim; - field = m_txtPadWidth->GetValue(); - if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) - adjusted.PadSize[0].Set(dim, adjusted.PadSize[0].GetY()); - field = m_txtPadLength->GetValue(); - if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) - adjusted.PadSize[0].Set(adjusted.PadSize[0].GetX(), dim); - /* if the pad shape is round or round+square, force the width and height - of that pad to be equal */ - if (adjusted.PadShape == 'C' || adjusted.PadShape == 'S') { - if (adjusted.PadSize[0].GetX() < adjusted.PadSize[0].GetY()) - dim = adjusted.PadSize[0].GetX(); - else - dim = adjusted.PadSize[0].GetY(); - adjusted.PadSize[0].Set(dim, dim); - } - - field = m_txtAuxPadWidth->GetValue(); - if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) - adjusted.PadSize[1].Set(dim, adjusted.PadSize[1].GetY()); - field = m_txtAuxPadLength->GetValue(); - if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) - adjusted.PadSize[1].Set(adjusted.PadSize[1].GetX(), dim); - - field = m_txtDrillSize->GetValue(); - if (field.length() > 0 && field.ToDouble(&dim)) - adjusted.DrillSize = (dim > 0.02) ? dim : 0.0; - - /* force the footprint to use mm (for convenience) */ - if (TranslateUnits(PartData[0], Footprint[0].Type >= VER_MM, true)) { - Footprint[0].Type = VER_MM; - adjusted.Type = VER_MM; /* footprint is converted to mm as well */ - } - AdjustPad(PartData[0], &Footprint[0], adjusted); - - /* if this footprint is based on a template and the template has the "STP" - variable set (Silk-To-Pad clearance), re-run the template */ - if (CheckTemplateVar(wxT("STP"))) { - ChangeBodyInfo(NULL); - TranslatePadInfo(&PartData[0], &Footprint[0]); - } + if (FieldEdited) { + ctrl->SetBackgroundColour(CHANGED); + ctrl->Refresh(); + FieldEdited = false; + PartEdited = true; + m_btnSavePart->Enable(true); + m_btnRevertPart->Enable(true); + + /* adjust the footprint */ + wxASSERT(PartData[0].Count() > 0); + FootprintInfo adjusted = Footprint[0]; + long idx; + wxString field; + + idx = m_choicePadShape->GetSelection(); + if (idx >= 0) + field = m_choicePadShape->GetString(idx); + if (field.CmpNoCase(wxT("Round")) == 0) + adjusted.PadShape = 'C'; + else if (field.CmpNoCase(wxT("Obround")) == 0) + adjusted.PadShape = 'O'; + else if (field.CmpNoCase(wxT("Rectangular")) == 0) + adjusted.PadShape = 'R'; + else if (field.CmpNoCase(wxT("Round + square")) == 0) + adjusted.PadShape = 'S'; + else if (field.CmpNoCase(wxT("Trapezoid")) == 0) + adjusted.PadShape = 'T'; + + /* for circular and square+round pads, the width & length should be the same */ + if (adjusted.PadShape == 'C' || adjusted.PadShape == 'S') { + if (ctrl == m_txtPadWidth) + m_txtPadLength->SetValue(m_txtPadWidth->GetValue()); + else if (ctrl == m_txtPadLength) + m_txtPadWidth->SetValue(m_txtPadLength->GetValue()); + } + + double dim; + field = m_txtPadWidth->GetValue(); + if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) + adjusted.PadSize[0].Set(dim, adjusted.PadSize[0].GetY()); + field = m_txtPadLength->GetValue(); + if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) + adjusted.PadSize[0].Set(adjusted.PadSize[0].GetX(), dim); + /* if the pad shape is round or round+square, force the width and height + of that pad to be equal */ + if (adjusted.PadShape == 'C' || adjusted.PadShape == 'S') { + if (adjusted.PadSize[0].GetX() < adjusted.PadSize[0].GetY()) + dim = adjusted.PadSize[0].GetX(); + else + dim = adjusted.PadSize[0].GetY(); + adjusted.PadSize[0].Set(dim, dim); + } + + field = m_txtAuxPadWidth->GetValue(); + if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) + adjusted.PadSize[1].Set(dim, adjusted.PadSize[1].GetY()); + field = m_txtAuxPadLength->GetValue(); + if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) + adjusted.PadSize[1].Set(adjusted.PadSize[1].GetX(), dim); + + field = m_txtDrillSize->GetValue(); + if (field.length() > 0 && field.ToDouble(&dim)) + adjusted.DrillSize = (dim > 0.02) ? dim : 0.0; + + /* force the footprint to use mm (for convenience) */ + if (TranslateUnits(PartData[0], Footprint[0].Type >= VER_MM, true)) { + Footprint[0].Type = VER_MM; + adjusted.Type = VER_MM; /* footprint is converted to mm as well */ + } + AdjustPad(PartData[0], &Footprint[0], adjusted); + + /* if this footprint is based on a template and the template has the "STP" + variable set (Silk-To-Pad clearance), re-run the template */ + if (CheckTemplateVar(wxT("STP"))) { + ChangeBodyInfo(NULL); + TranslatePadInfo(&PartData[0], &Footprint[0]); + } Update3DModel(PartData[0]); m_panelView->Refresh(); - } + } } void libmngrFrame::OnEnterPitchInfo(wxCommandEvent& event) { - ChangePitch((wxControl*)event.GetEventObject()); + ChangePitch((wxControl*)event.GetEventObject()); } void libmngrFrame::OnKillFocusPitchInfo(wxFocusEvent& event) { - ChangePitch((wxControl*)event.GetEventObject()); - event.Skip(); + ChangePitch((wxControl*)event.GetEventObject()); + event.Skip(); } void libmngrFrame::ChangePitch(wxControl* ctrl) { - if (FieldEdited) { - ctrl->SetBackgroundColour(CHANGED); - ctrl->Refresh(); - FieldEdited = false; - PartEdited = true; - m_btnSavePart->Enable(true); - m_btnRevertPart->Enable(true); - - double pitch; - wxString field = m_txtPitch->GetValue(); - if (field.length() == 0 || !field.ToDouble(&pitch) || pitch <= 0.02) - return; - if (Footprint[0].SOT23pitch && Footprint[0].RegPadCount == 3) - pitch *= 2; /* 3-pin SOT23 or variant */ - - /* force the footprint to use mm (for convenience) */ - wxASSERT(PartData[0].Count() > 0); - if (TranslateUnits(PartData[0], Footprint[0].Type >= VER_MM, true)) - Footprint[0].Type = VER_MM; - - wxASSERT((Footprint[0].MtxWidth == 0 && Footprint[0].MtxHeight == 0) - || (Footprint[0].MtxWidth > 0 && Footprint[0].MtxHeight > 0)); - if (Footprint[0].MtxWidth > 0) { - wxASSERT(!Footprint[0].SOT23pitch); - AdjustPitchGrid(PartData[0], Footprint[0].Pitch, pitch); - } else { - /* check the number of pins in each line */ - wxASSERT(Footprint[0].PadLines > 0); - int seq = Footprint[0].RegPadCount / Footprint[0].PadLines * Footprint[0].PadSequence; - if (Footprint[0].SOT23pitch) { - wxASSERT(Footprint[0].RegPadCount == 3 || Footprint[0].RegPadCount == 5); - wxASSERT(Footprint[0].PadSequence == 1); - seq = (Footprint[0].RegPadCount == 3) ? seq - 1 : seq + 1; - } - /* find initial direction */ - CoordPair startpin[4]; - int direction; /* 0=down, 1=right, 2=up, 3=left */ - if (Footprint[0].PitchVertical) - direction = (Footprint[0].PitchPins[0].GetY() < Footprint[0].PitchPins[1].GetY()) ? 0 : 2; - else - direction = (Footprint[0].PitchPins[0].GetX() < Footprint[0].PitchPins[1].GetX()) ? 1 : 3; - /* find start pins */ - startpin[direction] = Footprint[0].PitchPins[0]; - int opposing = (direction + 2) % 4; - if (opposing % 2 == 0 && Footprint[0].SpanHor > EPSILON) { - if (!Equal(startpin[direction].GetX(), Footprint[0].SpanHorPins[0].GetX(), TOLERANCE)) - startpin[opposing] = Footprint[0].SpanHorPins[0]; - else if (!Equal(startpin[direction].GetX(), Footprint[0].SpanHorPins[1].GetX(), TOLERANCE)) - startpin[opposing] = Footprint[0].SpanHorPins[1]; - } - if (opposing % 2 == 1 && Footprint[0].SpanVer > EPSILON) { - if (!Equal(startpin[direction].GetY(), Footprint[0].SpanVerPins[0].GetY(), TOLERANCE)) - startpin[opposing] = Footprint[0].SpanVerPins[0]; - else if (!Equal(startpin[direction].GetY(), Footprint[0].SpanVerPins[1].GetY(), TOLERANCE)) - startpin[opposing] = Footprint[0].SpanVerPins[1]; - } - if (direction % 2 == 0 && Footprint[0].SpanVer > EPSILON) { - /* positions 0 and 2 set, now set 1 and 3 */ - if (Footprint[0].SpanVerPins[0].GetY() < Footprint[0].SpanVerPins[1].GetY()) { - startpin[3] = Footprint[0].SpanVerPins[0]; - startpin[1] = Footprint[0].SpanVerPins[1]; - } else { - startpin[1] = Footprint[0].SpanVerPins[0]; - startpin[3] = Footprint[0].SpanVerPins[1]; - } - } - if (direction % 2 == 1 && Footprint[0].SpanHor > EPSILON) { - /* positions 1 and 3 set, now set 0 and 2 */ - if (Footprint[0].SpanHorPins[0].GetX() < Footprint[0].SpanHorPins[1].GetX()) { - startpin[0] = Footprint[0].SpanVerPins[0]; - startpin[2] = Footprint[0].SpanVerPins[1]; - } else { - startpin[2] = Footprint[0].SpanVerPins[0]; - startpin[0] = Footprint[0].SpanVerPins[1]; - } - } - - /* now modify the footprint */ - int base = 1; - for (int line = 1; line <= Footprint[0].PadLines; line++) { - switch (direction) { - case 0: - AdjustPitchVer(PartData[0], base, base + seq - 1, Footprint[0].PadSequence, - startpin[direction].GetX(), pitch); - break; - case 1: - AdjustPitchHor(PartData[0], base, base + seq - 1, Footprint[0].PadSequence, - startpin[direction].GetY(), pitch); - break; - case 2: - AdjustPitchVer(PartData[0], base, base + seq - 1, Footprint[0].PadSequence, - startpin[direction].GetX(), -pitch); - break; - case 3: - AdjustPitchHor(PartData[0], base, base + seq - 1, Footprint[0].PadSequence, - startpin[direction].GetY(), -pitch); - break; - } - if (Footprint[0].PadSequence == 1) { - base += seq; - if (Footprint[0].PadLines == 2) - direction = (direction + 2) % 4; - else - direction = (direction + 1) % 4; - /* for 5-pin SOT23 style, double the pitch for the next vertical row */ - if (direction == 2 && Footprint[0].SOT23pitch && Footprint[0].RegPadCount == 5) { - pitch *= 2; - seq -= 1; - wxASSERT(seq == 2); - } - } else { - /* for zig-zag style of dual-row pin headers (or similar) */ - base += 1; - /* keep the direction, but change the X or Y coordinate */ - int d = (Footprint[0].PadLines == 2) ? (direction + 2) % 4 : (direction + 1) % 4; - startpin[direction] = startpin[d]; - } - } - } /* if (MtxWidth > 0) */ - - /* if this footprint is based on a template and the template has the "STP" - variable set (Silk-To-Pad clearance), re-run the template */ - if (CheckTemplateVar(wxT("STP"))) - ChangeBodyInfo(NULL); - - TranslatePadInfo(&PartData[0], &Footprint[0]); + if (FieldEdited) { + ctrl->SetBackgroundColour(CHANGED); + ctrl->Refresh(); + FieldEdited = false; + PartEdited = true; + m_btnSavePart->Enable(true); + m_btnRevertPart->Enable(true); + + double pitch; + wxString field = m_txtPitch->GetValue(); + if (field.length() == 0 || !field.ToDouble(&pitch) || pitch <= 0.02) + return; + if (Footprint[0].SOT23pitch && Footprint[0].RegPadCount == 3) + pitch *= 2; /* 3-pin SOT23 or variant */ + + /* force the footprint to use mm (for convenience) */ + wxASSERT(PartData[0].Count() > 0); + if (TranslateUnits(PartData[0], Footprint[0].Type >= VER_MM, true)) + Footprint[0].Type = VER_MM; + + wxASSERT((Footprint[0].MtxWidth == 0 && Footprint[0].MtxHeight == 0) + || (Footprint[0].MtxWidth > 0 && Footprint[0].MtxHeight > 0)); + if (Footprint[0].MtxWidth > 0) { + wxASSERT(!Footprint[0].SOT23pitch); + AdjustPitchGrid(PartData[0], Footprint[0].Pitch, pitch); + } else { + /* check the number of pins in each line */ + wxASSERT(Footprint[0].PadLines > 0); + int seq = Footprint[0].RegPadCount / Footprint[0].PadLines * Footprint[0].PadSequence; + if (Footprint[0].SOT23pitch) { + wxASSERT(Footprint[0].RegPadCount == 3 || Footprint[0].RegPadCount == 5); + wxASSERT(Footprint[0].PadSequence == 1); + seq = (Footprint[0].RegPadCount == 3) ? seq - 1 : seq + 1; + } + /* find initial direction */ + CoordPair startpin[4]; + int direction; /* 0=down, 1=right, 2=up, 3=left */ + if (Footprint[0].PitchVertical) + direction = (Footprint[0].PitchPins[0].GetY() < Footprint[0].PitchPins[1].GetY()) ? 0 : 2; + else + direction = (Footprint[0].PitchPins[0].GetX() < Footprint[0].PitchPins[1].GetX()) ? 1 : 3; + /* find start pins */ + startpin[direction] = Footprint[0].PitchPins[0]; + int opposing = (direction + 2) % 4; + if (opposing % 2 == 0 && Footprint[0].SpanHor > EPSILON) { + if (!Equal(startpin[direction].GetX(), Footprint[0].SpanHorPins[0].GetX(), TOLERANCE)) + startpin[opposing] = Footprint[0].SpanHorPins[0]; + else if (!Equal(startpin[direction].GetX(), Footprint[0].SpanHorPins[1].GetX(), TOLERANCE)) + startpin[opposing] = Footprint[0].SpanHorPins[1]; + } + if (opposing % 2 == 1 && Footprint[0].SpanVer > EPSILON) { + if (!Equal(startpin[direction].GetY(), Footprint[0].SpanVerPins[0].GetY(), TOLERANCE)) + startpin[opposing] = Footprint[0].SpanVerPins[0]; + else if (!Equal(startpin[direction].GetY(), Footprint[0].SpanVerPins[1].GetY(), TOLERANCE)) + startpin[opposing] = Footprint[0].SpanVerPins[1]; + } + if (direction % 2 == 0 && Footprint[0].SpanVer > EPSILON) { + /* positions 0 and 2 set, now set 1 and 3 */ + if (Footprint[0].SpanVerPins[0].GetY() < Footprint[0].SpanVerPins[1].GetY()) { + startpin[3] = Footprint[0].SpanVerPins[0]; + startpin[1] = Footprint[0].SpanVerPins[1]; + } else { + startpin[1] = Footprint[0].SpanVerPins[0]; + startpin[3] = Footprint[0].SpanVerPins[1]; + } + } + if (direction % 2 == 1 && Footprint[0].SpanHor > EPSILON) { + /* positions 1 and 3 set, now set 0 and 2 */ + if (Footprint[0].SpanHorPins[0].GetX() < Footprint[0].SpanHorPins[1].GetX()) { + startpin[0] = Footprint[0].SpanVerPins[0]; + startpin[2] = Footprint[0].SpanVerPins[1]; + } else { + startpin[2] = Footprint[0].SpanVerPins[0]; + startpin[0] = Footprint[0].SpanVerPins[1]; + } + } + + /* now modify the footprint */ + int base = 1; + for (int line = 1; line <= Footprint[0].PadLines; line++) { + switch (direction) { + case 0: + AdjustPitchVer(PartData[0], base, base + seq - 1, Footprint[0].PadSequence, + startpin[direction].GetX(), pitch); + break; + case 1: + AdjustPitchHor(PartData[0], base, base + seq - 1, Footprint[0].PadSequence, + startpin[direction].GetY(), pitch); + break; + case 2: + AdjustPitchVer(PartData[0], base, base + seq - 1, Footprint[0].PadSequence, + startpin[direction].GetX(), -pitch); + break; + case 3: + AdjustPitchHor(PartData[0], base, base + seq - 1, Footprint[0].PadSequence, + startpin[direction].GetY(), -pitch); + break; + } + if (Footprint[0].PadSequence == 1) { + base += seq; + if (Footprint[0].PadLines == 2) + direction = (direction + 2) % 4; + else + direction = (direction + 1) % 4; + /* for 5-pin SOT23 style, double the pitch for the next vertical row */ + if (direction == 2 && Footprint[0].SOT23pitch && Footprint[0].RegPadCount == 5) { + pitch *= 2; + seq -= 1; + wxASSERT(seq == 2); + } + } else { + /* for zig-zag style of dual-row pin headers (or similar) */ + base += 1; + /* keep the direction, but change the X or Y coordinate */ + int d = (Footprint[0].PadLines == 2) ? (direction + 2) % 4 : (direction + 1) % 4; + startpin[direction] = startpin[d]; + } + } + } /* if (MtxWidth > 0) */ + + /* if this footprint is based on a template and the template has the "STP" + variable set (Silk-To-Pad clearance), re-run the template */ + if (CheckTemplateVar(wxT("STP"))) + ChangeBodyInfo(NULL); + + TranslatePadInfo(&PartData[0], &Footprint[0]); Update3DModel(PartData[0]); - m_panelView->Refresh(); - } + m_panelView->Refresh(); + } } void libmngrFrame::OnEnterSpanInfo(wxCommandEvent& event) { - ChangeSpan((wxControl*)event.GetEventObject()); + ChangeSpan((wxControl*)event.GetEventObject()); } void libmngrFrame::OnKillFocusSpanInfo(wxFocusEvent& event) { - ChangeSpan((wxControl*)event.GetEventObject()); - event.Skip(); + ChangeSpan((wxControl*)event.GetEventObject()); + event.Skip(); } void libmngrFrame::ChangeSpan(wxControl* ctrl) { - if (FieldEdited) { - ctrl->SetBackgroundColour(CHANGED); - ctrl->Refresh(); - FieldEdited = false; - PartEdited = true; - m_btnSavePart->Enable(true); - m_btnRevertPart->Enable(true); - - /* force the footprint to use mm (for convenience) */ - wxASSERT(PartData[0].Count() > 0); - if (TranslateUnits(PartData[0], Footprint[0].Type >= VER_MM, true)) - Footprint[0].Type = VER_MM; - - /* adjust the footprint */ - wxString field; - double dim, delta; - CoordPair p1, p2; - field = m_txtPadSpanX->GetValue(); - if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02 && !Equal(dim, Footprint[0].SpanHor, 0.01)) { - if (Footprint[0].SpanHorPins[0].GetX() < Footprint[0].SpanHorPins[1].GetX()) { - p1 = Footprint[0].SpanHorPins[0]; - p2 = Footprint[0].SpanHorPins[1]; - } else { - p1 = Footprint[0].SpanHorPins[1]; - p2 = Footprint[0].SpanHorPins[0]; - } - delta = (dim - Footprint[0].SpanHor) / 2; - MovePadHor(PartData[0], p1.GetX(), p1.GetX() - delta); - MovePadHor(PartData[0], p2.GetX(), p2.GetX() + delta); - Footprint[0].SpanHor = dim; - Footprint[0].SpanHorPins[0].Set(p1.GetX() - delta, p1.GetY()); - Footprint[0].SpanHorPins[1].Set(p2.GetX() + delta, p2.GetY()); - } - field = m_txtPadSpanY->GetValue(); - if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02 && !Equal(dim, Footprint[0].SpanVer, 0.01)) { - if (Footprint[0].SpanVerPins[0].GetY() < Footprint[0].SpanVerPins[1].GetY()) { - p1 = Footprint[0].SpanVerPins[0]; - p2 = Footprint[0].SpanVerPins[1]; - } else { - p1 = Footprint[0].SpanVerPins[1]; - p2 = Footprint[0].SpanVerPins[0]; - } - delta = (dim - Footprint[0].SpanVer) / 2; - MovePadVer(PartData[0], p1.GetY(), p1.GetY() - delta); - MovePadVer(PartData[0], p2.GetY(), p2.GetY() + delta); - Footprint[0].SpanVer = dim; - Footprint[0].SpanVerPins[0].Set(p1.GetX(), p1.GetY() - delta); - Footprint[0].SpanVerPins[1].Set(p2.GetX(), p2.GetY() + delta); - } - - /* if this footprint is based on a template and the template has the "STP" - variable set (Silk-To-Pad clearance), re-run the template */ - if (CheckTemplateVar(wxT("STP"))) - ChangeBodyInfo(NULL); - /* always re-translate the pad information, because the pitch anchor points - must remain correct */ - TranslatePadInfo(&PartData[0], &Footprint[0]); + if (FieldEdited) { + ctrl->SetBackgroundColour(CHANGED); + ctrl->Refresh(); + FieldEdited = false; + PartEdited = true; + m_btnSavePart->Enable(true); + m_btnRevertPart->Enable(true); + + /* force the footprint to use mm (for convenience) */ + wxASSERT(PartData[0].Count() > 0); + if (TranslateUnits(PartData[0], Footprint[0].Type >= VER_MM, true)) + Footprint[0].Type = VER_MM; + + /* adjust the footprint */ + wxString field; + double dim, delta; + CoordPair p1, p2; + field = m_txtPadSpanX->GetValue(); + if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02 && !Equal(dim, Footprint[0].SpanHor, 0.01)) { + if (Footprint[0].SpanHorPins[0].GetX() < Footprint[0].SpanHorPins[1].GetX()) { + p1 = Footprint[0].SpanHorPins[0]; + p2 = Footprint[0].SpanHorPins[1]; + } else { + p1 = Footprint[0].SpanHorPins[1]; + p2 = Footprint[0].SpanHorPins[0]; + } + delta = (dim - Footprint[0].SpanHor) / 2; + MovePadHor(PartData[0], p1.GetX(), p1.GetX() - delta); + MovePadHor(PartData[0], p2.GetX(), p2.GetX() + delta); + Footprint[0].SpanHor = dim; + Footprint[0].SpanHorPins[0].Set(p1.GetX() - delta, p1.GetY()); + Footprint[0].SpanHorPins[1].Set(p2.GetX() + delta, p2.GetY()); + } + field = m_txtPadSpanY->GetValue(); + if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02 && !Equal(dim, Footprint[0].SpanVer, 0.01)) { + if (Footprint[0].SpanVerPins[0].GetY() < Footprint[0].SpanVerPins[1].GetY()) { + p1 = Footprint[0].SpanVerPins[0]; + p2 = Footprint[0].SpanVerPins[1]; + } else { + p1 = Footprint[0].SpanVerPins[1]; + p2 = Footprint[0].SpanVerPins[0]; + } + delta = (dim - Footprint[0].SpanVer) / 2; + MovePadVer(PartData[0], p1.GetY(), p1.GetY() - delta); + MovePadVer(PartData[0], p2.GetY(), p2.GetY() + delta); + Footprint[0].SpanVer = dim; + Footprint[0].SpanVerPins[0].Set(p1.GetX(), p1.GetY() - delta); + Footprint[0].SpanVerPins[1].Set(p2.GetX(), p2.GetY() + delta); + } + + /* if this footprint is based on a template and the template has the "STP" + variable set (Silk-To-Pad clearance), re-run the template */ + if (CheckTemplateVar(wxT("STP"))) + ChangeBodyInfo(NULL); + /* always re-translate the pad information, because the pitch anchor points + must remain correct */ + TranslatePadInfo(&PartData[0], &Footprint[0]); Update3DModel(PartData[0]); - m_panelView->Refresh(); - } + m_panelView->Refresh(); + } } void libmngrFrame::OnEnterBodyInfo(wxCommandEvent& event) { - ChangeBodyInfo((wxControl*)event.GetEventObject()); + ChangeBodyInfo((wxControl*)event.GetEventObject()); } void libmngrFrame::OnKillFocusBodyInfo(wxFocusEvent& event) { - ChangeBodyInfo((wxControl*)event.GetEventObject()); - event.Skip(); + ChangeBodyInfo((wxControl*)event.GetEventObject()); + event.Skip(); } void libmngrFrame::ChangeBodyInfo(wxControl* ctrl) { - if (FieldEdited || !ctrl) { - if (ctrl) { - ctrl->SetBackgroundColour(CHANGED); - ctrl->Refresh(); - } - FieldEdited = false; - PartEdited = true; - m_btnSavePart->Enable(true); - m_btnRevertPart->Enable(true); + if (FieldEdited || !ctrl) { + if (ctrl) { + ctrl->SetBackgroundColour(CHANGED); + ctrl->Refresh(); + } + FieldEdited = false; + PartEdited = true; + m_btnSavePart->Enable(true); + m_btnRevertPart->Enable(true); - RebuildTemplate(); - m_panelView->Refresh(); - } + RebuildTemplate(); + m_panelView->Refresh(); + } } void libmngrFrame::OnEnterShapeHeight(wxCommandEvent& event) { - ChangeShape((wxControl*)event.GetEventObject()); + ChangeShape((wxControl*)event.GetEventObject()); } void libmngrFrame::OnKillFocusShapeHeight(wxFocusEvent& event) { - ChangeShape((wxControl*)event.GetEventObject()); - event.Skip(); + ChangeShape((wxControl*)event.GetEventObject()); + event.Skip(); } void libmngrFrame::ChangeShape(wxControl* ctrl) { if (FieldEdited) { - ctrl->SetBackgroundColour(CHANGED); - ctrl->Refresh(); - FieldEdited = false; - PartEdited = true; - m_btnSavePart->Enable(true); - m_btnRevertPart->Enable(true); + ctrl->SetBackgroundColour(CHANGED); + ctrl->Refresh(); + FieldEdited = false; + PartEdited = true; + m_btnSavePart->Enable(true); + m_btnRevertPart->Enable(true); Update3DModel(PartData[0]); m_panelView->Refresh(); - } + } } void libmngrFrame::OnEnterLabelField(wxCommandEvent& event) { - ChangeLabelInfo((wxControl*)event.GetEventObject()); + ChangeLabelInfo((wxControl*)event.GetEventObject()); } void libmngrFrame::OnKillFocusLabelField(wxFocusEvent& event) { - ChangeLabelInfo((wxControl*)event.GetEventObject()); - event.Skip(); + ChangeLabelInfo((wxControl*)event.GetEventObject()); + event.Skip(); } void libmngrFrame::OnLabelShowHide(wxCommandEvent& event) { - FieldEdited = true; - ChangeLabelInfo((wxControl*)event.GetEventObject()); + FieldEdited = true; + ChangeLabelInfo((wxControl*)event.GetEventObject()); } void libmngrFrame::ChangeLabelInfo(wxControl* ctrl) { - if (FieldEdited) { - ctrl->SetBackgroundColour(CHANGED); - ctrl->Refresh(); - FieldEdited = false; - PartEdited = true; - m_btnSavePart->Enable(true); - m_btnRevertPart->Enable(true); - - /* adjust the symbol or footprint */ - wxASSERT(PartData[0].Count() > 0); - LabelInfo adjusted = LabelData[0]; - - wxString field; - double dim; - - field = m_txtRefLabel->GetValue(); - if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) - adjusted.RefLabelSize = dim; - adjusted.RefLabelVisible = m_chkRefLabelVisible->GetValue(); - field = m_txtValueLabel->GetValue(); - if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) - adjusted.ValueLabelSize = dim; - adjusted.ValueLabelVisible = m_chkValueLabelVisible->GetValue(); - - /* force the footprint to use mm (for convenience) */ - if (TranslateUnits(PartData[0], Footprint[0].Type >= VER_MM, true)) - Footprint[0].Type = VER_MM; - SetTextLabelSize(PartData[0], adjusted, SymbolMode, true); - - /* if this is a footprint that is based on a template, re-run the - template because the text position is often a function of the text - size */ - if (!SymbolMode && GetTemplateName(PartData[0]).Length() > 0) { - ChangeBodyInfo(NULL); - TranslatePadInfo(&PartData[0], &Footprint[0]); - } - - m_panelView->Refresh(); - } -} - -bool libmngrFrame::CacheMetadata(const wxString& libname, const wxString& symname, bool force_export, const wxArrayString& module, + if (FieldEdited) { + ctrl->SetBackgroundColour(CHANGED); + ctrl->Refresh(); + FieldEdited = false; + PartEdited = true; + m_btnSavePart->Enable(true); + m_btnRevertPart->Enable(true); + + /* adjust the symbol or footprint */ + wxASSERT(PartData[0].Count() > 0); + LabelInfo adjusted = LabelData[0]; + + wxString field; + double dim; + + field = m_txtRefLabel->GetValue(); + if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) + adjusted.RefLabelSize = dim; + adjusted.RefLabelVisible = m_chkRefLabelVisible->GetValue(); + field = m_txtValueLabel->GetValue(); + if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) + adjusted.ValueLabelSize = dim; + adjusted.ValueLabelVisible = m_chkValueLabelVisible->GetValue(); + + /* force the footprint to use mm (for convenience) */ + if (TranslateUnits(PartData[0], Footprint[0].Type >= VER_MM, true)) + Footprint[0].Type = VER_MM; + SetTextLabelSize(PartData[0], adjusted, SymbolMode, true); + + /* if this is a footprint that is based on a template, re-run the + template because the text position is often a function of the text + size */ + if (!SymbolMode && GetTemplateName(PartData[0]).Length() > 0) { + ChangeBodyInfo(NULL); + TranslatePadInfo(&PartData[0], &Footprint[0]); + } + + m_panelView->Refresh(); + } +} + +bool libmngrFrame::CacheMetadata(const wxString& libname, const wxString& symname, bool force_export, const wxArrayString& module, const FootprintInfo& footprint) { - if (libname.CmpNoCase(LIB_REPOS) == 0) + if (libname.CmpNoCase(LIB_REPOS) == 0) return false; /* repository can serve as its own cache */ wxString dbpath = libname.AfterLast(wxT(DIRSEP_CHAR)); dbpath = dbpath.BeforeLast(wxT('.')) + wxT(".db"); /* change extension */ dbpath = theApp->GetUserDataPath() + wxT(DIRSEP_STR) + dbpath; - /* get the date/time stamp of the library (because it is stored, and because + /* get the date/time stamp of the library (because it is stored, and because it is used for checking whether the metadata must be updated */ time_t stamp; if (wxFileName::DirExists(libname)) { /* test time/date of footprint file */ - wxFileName fname(libname, symname + wxT(".kicad_mod")); + wxFileName fname(libname, symname + wxT(".kicad_mod")); stamp = wxFileModificationTime(fname.GetFullPath()); } else { /* test time/date of library file for legacy, or of single footprint for exported kicad_mod file */ @@ -6081,18 +6082,18 @@ bool libmngrFrame::CacheMetadata(const wxString& libname, const wxString& symnam /* footprint exists and its date/time stamp matches the stamp of the metadata -> no need to store it again */ unqlite_close(pDb); - return true; + return true; } } else if (rc != UNQLITE_NOTFOUND) { /* there was an I/O error -> don't try to store (because force_save was not set either) */ unqlite_close(pDb); - return true; + return true; } } /* collect all data into a string */ wxString data = wxString::Format(wxT("stamp=%ld\n"), (unsigned long)stamp); - + wxString string = GetDescription(module, SymbolMode); if (string.Length() > 0) data += wxT("description=") + string + wxT("\n"); @@ -6106,13 +6107,13 @@ bool libmngrFrame::CacheMetadata(const wxString& libname, const wxString& symnam if (footprint.Pitch > EPSILON) data += wxString::Format(wxT("pitch=%f\n"), footprint.Pitch); - double span = 0; - if (footprint.SpanHor <= EPSILON) - span = footprint.SpanVer; - else if (footprint.SpanVer <= EPSILON) - span = footprint.SpanHor; - else - span = footprint.PitchVertical ? footprint.SpanHor : footprint.SpanVer; + double span = 0; + if (footprint.SpanHor <= EPSILON) + span = footprint.SpanVer; + else if (footprint.SpanVer <= EPSILON) + span = footprint.SpanHor; + else + span = footprint.PitchVertical ? footprint.SpanHor : footprint.SpanVer; if (span > EPSILON) data += wxString::Format(wxT("span=%f\n"), span); @@ -6158,391 +6159,391 @@ bool libmngrFrame::CacheMetadata(const wxString& libname, const wxString& symnam bool libmngrFrame::SavePart(int index, wxListCtrl* list) { - if (FromRepository[0]) - return false; - wxASSERT(index >= 0); - - /* get the name of the symbol and the library it is in */ - wxString symbol = list->GetItemText(index); - wxListItem info; - info.SetId(index); - info.SetColumn(1); - info.SetMask(wxLIST_MASK_TEXT); - list->GetItem(info); - wxString filename = info.GetText(); - if (filename.CmpNoCase(LIB_REPOS) != 0) { - info.SetColumn(2); - list->GetItem(info); - filename = info.GetText(); - } - - wxASSERT(PartData[0].Count() > 0); - bool result; - if (SymbolMode) { - if (PinNamesEdited) { - /* verify pin numbers */ - wxASSERT(m_gridPinNames->GetNumberRows() == PinDataCount[0]); - for (int idx = 0; idx < m_gridPinNames->GetNumberRows(); idx++) { - if (PinData[0][idx].number.length() == 0) - wxMessageBox(wxT("No pin number for label: ") + PinData[0][idx].name); - for (int i = 0; i < idx; i++) { - // check duplicate pin number - if (PinData[0][i].number.CmpNoCase(PinData[0][idx].number) == 0) - wxMessageBox(wxT("Duplicate pin number: ") + PinData[0][idx].number); - // check that there is no other pin with the same name on the same part (except N.C.) - if (PinData[0][i].part == PinData[0][idx].part - && PinData[0][i].type != PinInfo::NC && PinData[0][idx].type != PinInfo::NC - && PinData[0][i].name.CmpNoCase(PinData[0][idx].name) == 0 + if (FromRepository[0]) + return false; + wxASSERT(index >= 0); + + /* get the name of the symbol and the library it is in */ + wxString symbol = list->GetItemText(index); + wxListItem info; + info.SetId(index); + info.SetColumn(1); + info.SetMask(wxLIST_MASK_TEXT); + list->GetItem(info); + wxString filename = info.GetText(); + if (filename.CmpNoCase(LIB_REPOS) != 0) { + info.SetColumn(2); + list->GetItem(info); + filename = info.GetText(); + } + + wxASSERT(PartData[0].Count() > 0); + bool result; + if (SymbolMode) { + if (PinNamesEdited) { + /* verify pin numbers */ + wxASSERT(m_gridPinNames->GetNumberRows() == PinDataCount[0]); + for (int idx = 0; idx < m_gridPinNames->GetNumberRows(); idx++) { + if (PinData[0][idx].number.length() == 0) + wxMessageBox(wxT("No pin number for label: ") + PinData[0][idx].name); + for (int i = 0; i < idx; i++) { + // check duplicate pin number + if (PinData[0][i].number.CmpNoCase(PinData[0][idx].number) == 0) + wxMessageBox(wxT("Duplicate pin number: ") + PinData[0][idx].number); + // check that there is no other pin with the same name on the same part (except N.C.) + if (PinData[0][i].part == PinData[0][idx].part + && PinData[0][i].type != PinInfo::NC && PinData[0][idx].type != PinInfo::NC + && PinData[0][i].name.CmpNoCase(PinData[0][idx].name) == 0 && PinData[0][i].name.Cmp(wxT("~")) != 0 && PinData[0][i].name.CmpNoCase(wxT("Vdd")) != 0 && PinData[0][i].name.CmpNoCase(wxT("Vss")) != 0 && PinData[0][i].name.CmpNoCase(wxT("GND")) != 0) - wxMessageBox(wxT("Duplicate pin name: ") + PinData[0][idx].name - + wxT("\nPins ") + PinData[0][i].number + wxT(" and ") + PinData[0][idx].number); - } - if (PinData[0][idx].part > 1) { - /* find the pin with the same name in section 1 (it should be found) */ - int base; - for (base = 0; base < PinDataCount[0]; base++) - if (PinData[0][base].part == 1 && PinData[0][base].name.CmpNoCase(PinData[0][idx].name) == 0) - break; - if (base < PinDataCount[0]) { - /* copy all other parameters from the pin at section 1 (keep only the pin number and the part */ - wxString pinnr = PinData[0][idx].number; - int part = PinData[0][idx].part; - PinData[0][idx] = PinData[0][base]; - PinData[0][idx].number = pinnr; - PinData[0][idx].part = part; - } else { - wxMessageBox(wxT("Pin number ") + PinData[0][idx].number + wxT(" with name ") + PinData[0][idx].name - + wxT(" has no equivalent in the base unit (unit 1)")); - } - } - } - } - wxASSERT(ExistSymbol(filename, symbol)); - RemoveSymbol(filename, symbol); - result = InsertSymbol(filename, symbol, PartData[0]); - } else { - int targettype = LibraryType(filename); - wxArrayString module; - if (Footprint[0].Type == VER_MM && targettype == VER_S_EXPR) { - /* translate the module to s-expression; this may be needed in the - case of footprints generated from templates, because the - templates are in legacy/mm format */ - TranslateToSexpr(&module, PartData[0]); - } else { - module = PartData[0]; - } + wxMessageBox(wxT("Duplicate pin name: ") + PinData[0][idx].name + + wxT("\nPins ") + PinData[0][i].number + wxT(" and ") + PinData[0][idx].number); + } + if (PinData[0][idx].part > 1) { + /* find the pin with the same name in section 1 (it should be found) */ + int base; + for (base = 0; base < PinDataCount[0]; base++) + if (PinData[0][base].part == 1 && PinData[0][base].name.CmpNoCase(PinData[0][idx].name) == 0) + break; + if (base < PinDataCount[0]) { + /* copy all other parameters from the pin at section 1 (keep only the pin number and the part */ + wxString pinnr = PinData[0][idx].number; + int part = PinData[0][idx].part; + PinData[0][idx] = PinData[0][base]; + PinData[0][idx].number = pinnr; + PinData[0][idx].part = part; + } else { + wxMessageBox(wxT("Pin number ") + PinData[0][idx].number + wxT(" with name ") + PinData[0][idx].name + + wxT(" has no equivalent in the base unit (unit 1)")); + } + } + } + } + wxASSERT(ExistSymbol(filename, symbol)); + RemoveSymbol(filename, symbol); + result = InsertSymbol(filename, symbol, PartData[0]); + } else { + int targettype = LibraryType(filename); + wxArrayString module; + if (Footprint[0].Type == VER_MM && targettype == VER_S_EXPR) { + /* translate the module to s-expression; this may be needed in the + case of footprints generated from templates, because the + templates are in legacy/mm format */ + TranslateToSexpr(&module, PartData[0]); + } else { + module = PartData[0]; + } //??? check whether all pads are SMD pads; if so, toggle type of the module to SMD - wxASSERT(ExistFootprint(filename, symbol)); - RemoveFootprint(filename, symbol); - result = InsertFootprint(filename, symbol, module, Footprint[0].Type >= VER_MM); + wxASSERT(ExistFootprint(filename, symbol)); + RemoveFootprint(filename, symbol); + result = InsertFootprint(filename, symbol, module, Footprint[0].Type >= VER_MM); /* cache the metadata (pitch, courtyard, descriptions) */ CacheMetadata(filename, symbol, true, module, Footprint[0]); - } - if (result) { - PartEdited = false; - } else { - wxMessageBox(wxT("Operation failed.")); - return false; - } - - wxString templatename = GetTemplateName(PartData[0]); - wxString vrmlpath = GetVRMLPath(filename, PartData[0]); - if (vrmlpath.Length() > 0 && templatename.length() > 0) { - /* re-generate 3D model - first, set all variables to the defaults of the template */ - wxString description = m_txtDescription->GetValue(); - RPNexpression rpn; - SetVarDefaults(&rpn, templatename, symbol, description); - SetVarsFromFields(&rpn, false); - /* get the template to use */ - wxString modelname; + } + if (result) { + PartEdited = false; + } else { + wxMessageBox(wxT("Operation failed.")); + return false; + } + + wxString templatename = GetTemplateName(PartData[0]); + wxString vrmlpath = GetVRMLPath(filename, PartData[0]); + if (vrmlpath.Length() > 0 && templatename.length() > 0) { + /* re-generate 3D model + first, set all variables to the defaults of the template */ + wxString description = m_txtDescription->GetValue(); + RPNexpression rpn; + SetVarDefaults(&rpn, templatename, symbol, description); + SetVarsFromFields(&rpn, false); + /* get the template to use */ + wxString modelname; int idx = m_choiceShape->GetCurrentSelection(); - if (idx >= 0 && idx < (int)m_choiceShape->GetCount()) { + if (idx >= 0 && idx < (int)m_choiceShape->GetCount()) { modelname = m_choiceShape->GetString(idx); } else { modelname = GetTemplateHeaderField(templatename, wxT("model"), SymbolMode); - if (modelname.length() == 0) - modelname = templatename; - else - modelname = modelname.BeforeFirst(wxT(' ')); + if (modelname.length() == 0) + modelname = templatename; + else + modelname = modelname.BeforeFirst(wxT(' ')); } - VRMLFromTemplate(vrmlpath, modelname, rpn); - } + VRMLFromTemplate(vrmlpath, modelname, rpn); + } - return true; + return true; } bool libmngrFrame::CheckSavePart() { - if (!PartEdited) - return true; /* nothing changed (so nothing to save) */ + if (!PartEdited) + return true; /* nothing changed (so nothing to save) */ - wxString msg; - if (SymbolMode) - msg = wxT("Do you want to save the current symbol first?"); - else - msg = wxT("Do you want to save the footprint symbol first?"); - int reply = wxMessageBox(msg, wxT("Unsaved changes"), wxYES_NO | wxICON_QUESTION); - if (reply == wxYES) { - wxASSERT(SelectedPartLeft == -1 || SelectedPartRight == -1); - long index = (SelectedPartLeft >= 0) ? SelectedPartLeft : SelectedPartRight; - wxListCtrl* list = (SelectedPartLeft >= 0) ? m_listModulesLeft : m_listModulesRight; - return SavePart(index, list); - } - return false; + wxString msg; + if (SymbolMode) + msg = wxT("Do you want to save the current symbol first?"); + else + msg = wxT("Do you want to save the footprint symbol first?"); + int reply = wxMessageBox(msg, wxT("Unsaved changes"), wxYES_NO | wxICON_QUESTION); + if (reply == wxYES) { + wxASSERT(SelectedPartLeft == -1 || SelectedPartRight == -1); + long index = (SelectedPartLeft >= 0) ? SelectedPartLeft : SelectedPartRight; + wxListCtrl* list = (SelectedPartLeft >= 0) ? m_listModulesLeft : m_listModulesRight; + return SavePart(index, list); + } + return false; } void libmngrFrame::OnSavePart(wxCommandEvent& /*event*/) { - long idxleft = m_listModulesLeft->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - long idxright = m_listModulesRight->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - wxASSERT(idxleft == -1 || idxright == -1); - long index; - wxListCtrl* list; - if (idxleft >= 0) { - list = m_listModulesLeft; - index = idxleft; - } else { - list = m_listModulesRight; - index = idxright; - } - wxASSERT(index >= 0); - wxASSERT(!FromRepository[0]); - SavePart(index, list); - - /* reload the part just saved */ - LoadPart(index, list, 0, 0); - UpdateDetails(0); + long idxleft = m_listModulesLeft->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + long idxright = m_listModulesRight->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + wxASSERT(idxleft == -1 || idxright == -1); + long index; + wxListCtrl* list; + if (idxleft >= 0) { + list = m_listModulesLeft; + index = idxleft; + } else { + list = m_listModulesRight; + index = idxright; + } + wxASSERT(index >= 0); + wxASSERT(!FromRepository[0]); + SavePart(index, list); + + /* reload the part just saved */ + LoadPart(index, list, 0, 0); + UpdateDetails(0); Update3DModel(PartData[0]); - m_panelView->Refresh(); - if (SymbolMode) - m_statusBar->SetStatusText(wxT("Saved modified symbol")); - else - m_statusBar->SetStatusText(wxT("Saved modified footprint")); + m_panelView->Refresh(); + if (SymbolMode) + m_statusBar->SetStatusText(wxT("Saved modified symbol")); + else + m_statusBar->SetStatusText(wxT("Saved modified footprint")); } void libmngrFrame::OnRevertPart(wxCommandEvent& /*event*/) { - long idxleft = m_listModulesLeft->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - long idxright = m_listModulesRight->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - wxASSERT(idxleft == -1 || idxright == -1); - if (idxleft >= 0) - LoadPart(idxleft, m_listModulesLeft, m_choiceModuleLeft, 0); - else - LoadPart(idxright, m_listModulesRight, m_choiceModuleRight, 0); - UpdateDetails(0); + long idxleft = m_listModulesLeft->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + long idxright = m_listModulesRight->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + wxASSERT(idxleft == -1 || idxright == -1); + if (idxleft >= 0) + LoadPart(idxleft, m_listModulesLeft, m_choiceModuleLeft, 0); + else + LoadPart(idxright, m_listModulesRight, m_choiceModuleRight, 0); + UpdateDetails(0); Update3DModel(PartData[0]); - m_panelView->Refresh(); - m_statusBar->SetStatusText(wxT("Changes reverted")); + m_panelView->Refresh(); + m_statusBar->SetStatusText(wxT("Changes reverted")); } bool libmngrFrame::CheckTemplateVar(const wxString& varname) { - wxASSERT(PartData[0].Count() > 0); - wxString templatename = GetTemplateName(PartData[0]); - if (templatename.length() == 0) - return false; + wxASSERT(PartData[0].Count() > 0); + wxString templatename = GetTemplateName(PartData[0]); + if (templatename.length() == 0) + return false; - if (varname.IsEmpty()) - return true; + if (varname.IsEmpty()) + return true; - wxString field = GetTemplateHeaderField(templatename, wxT("param"), SymbolMode); - if (field.length() == 0) - return false; - return (field.Find(wxT("@") + varname) >= 0); + wxString field = GetTemplateHeaderField(templatename, wxT("param"), SymbolMode); + if (field.length() == 0) + return false; + return (field.Find(wxT("@") + varname) >= 0); } bool libmngrFrame::SetVarDefaults(RPNexpression *rpn, const wxString& templatename, - const wxString& footprintname, const wxString& description, - const wxString& prefix, const wxString& tags, bool silent) -{ - /* first set the defaults on the parameter line */ - wxASSERT(templatename.length() > 0); - wxString field = GetTemplateHeaderField(templatename, wxT("param"), SymbolMode); - if (field.length() > 0) { - rpn->Set(field.utf8_str()); - RPN_ERROR err = rpn->Parse(); - if (err != RPN_EMPTY && !silent) - wxMessageBox(wxT("The '#param' line in the template has an error.")); - } - - /* then set the defaults from the user settings (possibly overriding those - of the #param line) */ - wxFileConfig *config = new wxFileConfig(APP_NAME, VENDOR_NAME, theApp->GetINIPath()); - config->SetPath(wxT("/template")); - wxString varname; - long token; - bool ok = config->GetFirstEntry(varname, token); - while (ok) { - double val; - if (config->Read(varname, &val)) - rpn->SetVariable(RPNvariable(varname.utf8_str(), val)); - ok = config->GetNextEntry(varname, token); - } - delete config; - - rpn->SetVariable(RPNvariable("NAME", footprintname.utf8_str())); - rpn->SetVariable(RPNvariable("DESCR", description.utf8_str())); - rpn->SetVariable(RPNvariable("REF", prefix.utf8_str())); - rpn->SetVariable(RPNvariable("TAGS", tags.utf8_str())); - - /* set any pin section criterions */ - if (SymbolMode) { - for (int index = 0; index < sizearray(CustomPinSections[0]); index++) { - if (CustomPinSections[0][index].IsValid()) { - wxString name = wxString::Format(wxT("PSC:%d"), index + PinInfo::LeftCustom); - rpn->SetVariable(RPNvariable(name.utf8_str(), CustomPinSections[0][index].Criterion())); - } - } - } - - return true; + const wxString& footprintname, const wxString& description, + const wxString& prefix, const wxString& tags, bool silent) +{ + /* first set the defaults on the parameter line */ + wxASSERT(templatename.length() > 0); + wxString field = GetTemplateHeaderField(templatename, wxT("param"), SymbolMode); + if (field.length() > 0) { + rpn->Set(field.utf8_str()); + RPN_ERROR err = rpn->Parse(); + if (err != RPN_EMPTY && !silent) + wxMessageBox(wxT("The '#param' line in the template has an error.")); + } + + /* then set the defaults from the user settings (possibly overriding those + of the #param line) */ + wxFileConfig *config = new wxFileConfig(APP_NAME, VENDOR_NAME, theApp->GetINIPath()); + config->SetPath(wxT("/template")); + wxString varname; + long token; + bool ok = config->GetFirstEntry(varname, token); + while (ok) { + double val; + if (config->Read(varname, &val)) + rpn->SetVariable(RPNvariable(varname.utf8_str(), val)); + ok = config->GetNextEntry(varname, token); + } + delete config; + + rpn->SetVariable(RPNvariable("NAME", footprintname.utf8_str())); + rpn->SetVariable(RPNvariable("DESCR", description.utf8_str())); + rpn->SetVariable(RPNvariable("REF", prefix.utf8_str())); + rpn->SetVariable(RPNvariable("TAGS", tags.utf8_str())); + + /* set any pin section criterions */ + if (SymbolMode) { + for (int index = 0; index < sizearray(CustomPinSections[0]); index++) { + if (CustomPinSections[0][index].IsValid()) { + wxString name = wxString::Format(wxT("PSC:%d"), index + PinInfo::LeftCustom); + rpn->SetVariable(RPNvariable(name.utf8_str(), CustomPinSections[0][index].Criterion())); + } + } + } + + return true; } bool libmngrFrame::SetVarsFromFields(RPNexpression *rpn, bool SymbolMode) { - long val; - double dim; - - wxString field = m_txtPadCount->GetValue(); - if (field.length() > 0 && field.ToLong(&val) && val > 0) - rpn->SetVariable(RPNvariable("PT", val)); - field = m_txtBodyLength->GetValue(); - if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) - rpn->SetVariable(RPNvariable("BL", dim)); - field = m_txtBodyWidth->GetValue(); - if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) - rpn->SetVariable(RPNvariable("BW", dim)); - field = m_txtRefLabel->GetValue(); - if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) { - if (!m_chkRefLabelVisible->GetValue()) - dim = -dim; - rpn->SetVariable(RPNvariable("TSR", dim)); - } - field = m_txtValueLabel->GetValue(); - if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) { - if (!m_chkValueLabelVisible->GetValue()) - dim = -dim; - rpn->SetVariable(RPNvariable("TSV", dim)); - } - - if (!SymbolMode) { - field = m_txtPadWidth->GetValue(); - if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) - rpn->SetVariable(RPNvariable("PW", dim)); - field = m_txtPadLength->GetValue(); - if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) - rpn->SetVariable(RPNvariable("PL", dim)); - field = m_txtAuxPadLength->GetValue(); - if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) - rpn->SetVariable(RPNvariable("PLA", dim)); - field = m_txtAuxPadWidth->GetValue(); - if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) - rpn->SetVariable(RPNvariable("PWA", dim)); - field = m_txtPitch->GetValue(); - if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) - rpn->SetVariable(RPNvariable("PP", dim)); - field = m_txtPadSpanX->GetValue(); - if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) - rpn->SetVariable(RPNvariable("SH", dim)); - field = m_txtPadSpanY->GetValue(); - if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) - rpn->SetVariable(RPNvariable("SV", dim)); - field = m_txtDrillSize->GetValue(); - if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) - rpn->SetVariable(RPNvariable("DS", dim)); - field = m_txtShapeHeight->GetValue(); - if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) - rpn->SetVariable(RPNvariable("BH", dim)); + long val; + double dim; + + wxString field = m_txtPadCount->GetValue(); + if (field.length() > 0 && field.ToLong(&val) && val > 0) + rpn->SetVariable(RPNvariable("PT", val)); + field = m_txtBodyLength->GetValue(); + if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) + rpn->SetVariable(RPNvariable("BL", dim)); + field = m_txtBodyWidth->GetValue(); + if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) + rpn->SetVariable(RPNvariable("BW", dim)); + field = m_txtRefLabel->GetValue(); + if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) { + if (!m_chkRefLabelVisible->GetValue()) + dim = -dim; + rpn->SetVariable(RPNvariable("TSR", dim)); + } + field = m_txtValueLabel->GetValue(); + if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) { + if (!m_chkValueLabelVisible->GetValue()) + dim = -dim; + rpn->SetVariable(RPNvariable("TSV", dim)); + } + + if (!SymbolMode) { + field = m_txtPadWidth->GetValue(); + if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) + rpn->SetVariable(RPNvariable("PW", dim)); + field = m_txtPadLength->GetValue(); + if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) + rpn->SetVariable(RPNvariable("PL", dim)); + field = m_txtAuxPadLength->GetValue(); + if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) + rpn->SetVariable(RPNvariable("PLA", dim)); + field = m_txtAuxPadWidth->GetValue(); + if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) + rpn->SetVariable(RPNvariable("PWA", dim)); + field = m_txtPitch->GetValue(); + if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) + rpn->SetVariable(RPNvariable("PP", dim)); + field = m_txtPadSpanX->GetValue(); + if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) + rpn->SetVariable(RPNvariable("SH", dim)); + field = m_txtPadSpanY->GetValue(); + if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) + rpn->SetVariable(RPNvariable("SV", dim)); + field = m_txtDrillSize->GetValue(); + if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) + rpn->SetVariable(RPNvariable("DS", dim)); + field = m_txtShapeHeight->GetValue(); + if (field.length() > 0 && field.ToDouble(&dim) && dim > 0.02) + rpn->SetVariable(RPNvariable("BH", dim)); /* the pitch direction is not in a field; it is set from the parsed info */ rpn->SetVariable(RPNvariable("PPDIR", Footprint[0].PitchVertical ? 1 : 0)); - } - return true; + } + return true; } void libmngrFrame::SetVarsFromTemplate(RPNexpression *rpn, const wxString& templatename, bool SymbolMode) { - wxString field = GetTemplateHeaderField(templatename, wxT("flags"), SymbolMode); + wxString field = GetTemplateHeaderField(templatename, wxT("flags"), SymbolMode); int pos = field.Find(wxT("aux-pad")); - if (pos >= 0) { - wxString params = field.Mid(pos); - params = params.AfterFirst(wxT('(')); - params = params.BeforeFirst(wxT(')')); + if (pos >= 0) { + wxString params = field.Mid(pos); + params = params.AfterFirst(wxT('(')); + params = params.BeforeFirst(wxT(')')); wxString type = params.BeforeFirst(wxT(',')); /* should be "mechanic", "flag" or "flag-nc" */ - wxString pm = params.AfterFirst(wxT(',')); - long padcount = 0; + wxString pm = params.AfterFirst(wxT(',')); + long padcount = 0; if (pm.Cmp(wxT("*")) == 0) padcount = 1; else - pm.ToLong(&padcount); + pm.ToLong(&padcount); if (type.CmpNoCase(wxT("flag")) == 0) padcount--; /* for a flag (connected exposed pad), one pad is included in the "normal" pad count */ - rpn->SetVariable(RPNvariable("PTA", padcount)); - } + rpn->SetVariable(RPNvariable("PTA", padcount)); + } } bool libmngrFrame::RebuildTemplate() { - wxASSERT(PartData[0].Count() > 0); - wxString templatename = GetTemplateName(PartData[0]); - wxASSERT(templatename.length() > 0); /* if there is no template, the fields for - the body size are read-only */ - if (templatename.length() == 0) - return false; - - /* first, set all variables to the defaults of the template */ - wxString leftmod = GetSelection(m_listModulesLeft); - wxString rightmod = GetSelection(m_listModulesRight); - wxASSERT(leftmod.IsEmpty() || rightmod.IsEmpty()); - wxString footprintname = (leftmod.length() > 0) ? leftmod : rightmod; - wxString description = m_txtDescription->GetValue(); + wxASSERT(PartData[0].Count() > 0); + wxString templatename = GetTemplateName(PartData[0]); + wxASSERT(templatename.length() > 0); /* if there is no template, the fields for + the body size are read-only */ + if (templatename.length() == 0) + return false; + + /* first, set all variables to the defaults of the template */ + wxString leftmod = GetSelection(m_listModulesLeft); + wxString rightmod = GetSelection(m_listModulesRight); + wxASSERT(leftmod.IsEmpty() || rightmod.IsEmpty()); + wxString footprintname = (leftmod.length() > 0) ? leftmod : rightmod; + wxString description = m_txtDescription->GetValue(); wxString tags = m_txtAlias->GetValue(); - wxString prefix = wxEmptyString; - if (SymbolMode) - prefix = GetPrefix(PartData[0]); - RPNexpression rpn; - if (SymbolMode) - rpn.SetVariable(RPNvariable("PT", PinDataCount[0])); /* other defaults depend on the correct pin count */ - SetVarDefaults(&rpn, templatename, footprintname, description, prefix, tags, true); - - /* then, update the variables from the fields - update all fields, because the body size may depend on other settings, - such as pitch, too */ - SetVarsFromFields(&rpn, SymbolMode); - SetVarsFromTemplate(&rpn, templatename, SymbolMode); - - /* refresh the footprint from the template, but only partially (by default) */ - wxString field = GetTemplateHeaderField(templatename, wxT("flags"), SymbolMode); - bool bodyonly = (field.Find(wxT("rebuild")) == wxNOT_FOUND); - - wxArrayString templatemodule; - LoadTemplate(templatename, &templatemodule, SymbolMode); - bool result; - if (SymbolMode) { - /* save the current aliases and footprint list, because these are absent from the templates */ - wxString aliases = GetAliases(PartData[0]); - wxString footprints = GetFootprints(PartData[0]); - result = SymbolFromTemplate(&PartData[0], templatemodule, rpn, PinData[0], PinDataCount[0]); - if (aliases.Length() > 0) - SetAliases(PartData[0], aliases); - if (footprints.Length() > 0) - SetFootprints(PartData[0], footprints); - } else { - /* since the footprint is only partially regenerated, the other part must - be converted to mm (and legacy) */ - if (Footprint[0].Type == VER_MIL) { - TranslateUnits(PartData[0], false, true); - } else if (Footprint[0].Type == VER_S_EXPR) { - wxArrayString partdata; - TranslateToLegacy(&partdata, PartData[0]); - PartData[0] = partdata; - } - Footprint[0].Type = VER_MM; - result = FootprintFromTemplate(&PartData[0], templatemodule, rpn, bodyonly); + wxString prefix = wxEmptyString; + if (SymbolMode) + prefix = GetPrefix(PartData[0]); + RPNexpression rpn; + if (SymbolMode) + rpn.SetVariable(RPNvariable("PT", PinDataCount[0])); /* other defaults depend on the correct pin count */ + SetVarDefaults(&rpn, templatename, footprintname, description, prefix, tags, true); + + /* then, update the variables from the fields + update all fields, because the body size may depend on other settings, + such as pitch, too */ + SetVarsFromFields(&rpn, SymbolMode); + SetVarsFromTemplate(&rpn, templatename, SymbolMode); + + /* refresh the footprint from the template, but only partially (by default) */ + wxString field = GetTemplateHeaderField(templatename, wxT("flags"), SymbolMode); + bool bodyonly = (field.Find(wxT("rebuild")) == wxNOT_FOUND); + + wxArrayString templatemodule; + LoadTemplate(templatename, &templatemodule, SymbolMode); + bool result; + if (SymbolMode) { + /* save the current aliases and footprint list, because these are absent from the templates */ + wxString aliases = GetAliases(PartData[0]); + wxString footprints = GetFootprints(PartData[0]); + result = SymbolFromTemplate(&PartData[0], templatemodule, rpn, PinData[0], PinDataCount[0]); + if (aliases.Length() > 0) + SetAliases(PartData[0], aliases); + if (footprints.Length() > 0) + SetFootprints(PartData[0], footprints); + } else { + /* since the footprint is only partially regenerated, the other part must + be converted to mm (and legacy) */ + if (Footprint[0].Type == VER_MIL) { + TranslateUnits(PartData[0], false, true); + } else if (Footprint[0].Type == VER_S_EXPR) { + wxArrayString partdata; + TranslateToLegacy(&partdata, PartData[0]); + PartData[0] = partdata; + } + Footprint[0].Type = VER_MM; + result = FootprintFromTemplate(&PartData[0], templatemodule, rpn, bodyonly); Update3DModel(PartData[0]); - } - return result; + } + return result; } bool libmngrFrame::Update3DModel(const wxArrayString& module) @@ -6556,7 +6557,7 @@ bool libmngrFrame::Update3DModel(const wxArrayString& module) return false; wxASSERT(!SymbolMode && !CompareMode); /* ModelMode can only be made active for footprints and no comparison */ wxString templatename = GetTemplateName(module); - wxString vrmlpath = GetVRMLPath(wxEmptyString, module); /* only to check that a VRML template is defined for this footprint */ + wxString vrmlpath = GetVRMLPath(wxEmptyString, module); /* only to check that a VRML template is defined for this footprint */ /* if the VRML model is based on a template, regenerate it in a temporary file, so that the model is guaranteed to have the correct dimentsions; if there is no template, but there is a VRML model, show that model (but disable the edit fields) */ @@ -6575,21 +6576,21 @@ bool libmngrFrame::Update3DModel(const wxArrayString& module) /* re-generate 3D model */ if (UseTempModel) { - /* first, set all variables to the defaults of the template */ + /* first, set all variables to the defaults of the template */ RPNexpression rpn; SetVarDefaults(&rpn, templatename, wxEmptyString, wxEmptyString); SetVarsFromFields(&rpn, false); /* get the template to use */ - wxString modelname; + wxString modelname; int idx = m_choiceShape->GetCurrentSelection(); - if (idx >= 0 && idx < (int)m_choiceShape->GetCount()) { + if (idx >= 0 && idx < (int)m_choiceShape->GetCount()) { modelname = m_choiceShape->GetString(idx); } else { modelname = GetTemplateHeaderField(templatename, wxT("model"), SymbolMode); - if (modelname.length() == 0) - modelname = templatename; - else - modelname = modelname.BeforeFirst(wxT(' ')); + if (modelname.length() == 0) + modelname = templatename; + else + modelname = modelname.BeforeFirst(wxT(' ')); } /* create the VRML file as a temporary file, then load */ @@ -6612,318 +6613,318 @@ bool libmngrFrame::Update3DModel(const wxArrayString& module) void libmngrFrame::UpdateDetails(int fp) { - /* reset all fields and colours */ - m_txtDescription->SetToolTip(wxEmptyString); - m_txtDescription->SetValue(wxEmptyString); - m_txtAlias->SetValue(wxEmptyString); - m_txtDescription->SetEditable(false); - m_txtAlias->SetEditable(false); - m_txtDescription->SetBackgroundColour(PROTECTED); - m_txtAlias->SetBackgroundColour(PROTECTED); - if (SymbolMode) { - m_txtFootprintFilter->SetValue(wxEmptyString); - m_txtPadCount->SetValue(wxEmptyString); - m_gridPinNames->ClearGrid(); - m_gridPinNames->SetColLabelSize(0); - if (m_gridPinNames->GetNumberRows() > 0) - m_gridPinNames->DeleteRows(0, m_gridPinNames->GetNumberRows()); - wxSizer* sizer = m_gridPinNames->GetContainingSizer(); - m_txtBodyLength->SetValue(wxEmptyString); - m_txtBodyWidth->SetValue(wxEmptyString); - m_txtRefLabel->SetValue(wxEmptyString); - m_chkRefLabelVisible->SetValue(false); - m_txtValueLabel->SetValue(wxEmptyString); - m_chkValueLabelVisible->SetValue(false); - wxASSERT(sizer != 0); - sizer->Layout(); - - m_txtFootprintFilter->SetEditable(false); - m_txtPadCount->SetEditable(false); - m_gridPinNames->EnableEditing(false); - m_txtBodyLength->SetEditable(false); - m_txtBodyWidth->SetEditable(false); - m_txtRefLabel->SetEditable(false); - m_chkRefLabelVisible->Enable(false); - m_txtValueLabel->SetEditable(false); - m_chkValueLabelVisible->Enable(false); - - m_txtFootprintFilter->SetBackgroundColour(PROTECTED); - m_txtPadCount->SetBackgroundColour(PROTECTED); - m_gridPinNames->SetBackgroundColour(PROTECTED); - m_txtBodyLength->SetBackgroundColour(PROTECTED); - m_txtBodyWidth->SetBackgroundColour(PROTECTED); - m_txtRefLabel->SetBackgroundColour(PROTECTED); - m_chkRefLabelVisible->SetBackgroundColour(wxNullColour); - m_txtValueLabel->SetBackgroundColour(PROTECTED); - m_chkValueLabelVisible->SetBackgroundColour(wxNullColour); - } else { + /* reset all fields and colours */ + m_txtDescription->SetToolTip(wxEmptyString); + m_txtDescription->SetValue(wxEmptyString); + m_txtAlias->SetValue(wxEmptyString); + m_txtDescription->SetEditable(false); + m_txtAlias->SetEditable(false); + m_txtDescription->SetBackgroundColour(PROTECTED); + m_txtAlias->SetBackgroundColour(PROTECTED); + if (SymbolMode) { + m_txtFootprintFilter->SetValue(wxEmptyString); + m_txtPadCount->SetValue(wxEmptyString); + m_gridPinNames->ClearGrid(); + m_gridPinNames->SetColLabelSize(0); + if (m_gridPinNames->GetNumberRows() > 0) + m_gridPinNames->DeleteRows(0, m_gridPinNames->GetNumberRows()); + wxSizer* sizer = m_gridPinNames->GetContainingSizer(); + m_txtBodyLength->SetValue(wxEmptyString); + m_txtBodyWidth->SetValue(wxEmptyString); + m_txtRefLabel->SetValue(wxEmptyString); + m_chkRefLabelVisible->SetValue(false); + m_txtValueLabel->SetValue(wxEmptyString); + m_chkValueLabelVisible->SetValue(false); + wxASSERT(sizer != 0); + sizer->Layout(); + + m_txtFootprintFilter->SetEditable(false); + m_txtPadCount->SetEditable(false); + m_gridPinNames->EnableEditing(false); + m_txtBodyLength->SetEditable(false); + m_txtBodyWidth->SetEditable(false); + m_txtRefLabel->SetEditable(false); + m_chkRefLabelVisible->Enable(false); + m_txtValueLabel->SetEditable(false); + m_chkValueLabelVisible->Enable(false); + + m_txtFootprintFilter->SetBackgroundColour(PROTECTED); + m_txtPadCount->SetBackgroundColour(PROTECTED); + m_gridPinNames->SetBackgroundColour(PROTECTED); + m_txtBodyLength->SetBackgroundColour(PROTECTED); + m_txtBodyWidth->SetBackgroundColour(PROTECTED); + m_txtRefLabel->SetBackgroundColour(PROTECTED); + m_chkRefLabelVisible->SetBackgroundColour(wxNullColour); + m_txtValueLabel->SetBackgroundColour(PROTECTED); + m_chkValueLabelVisible->SetBackgroundColour(wxNullColour); + } else { m_choiceShape->Clear(); - m_txtPadCount->SetValue(wxEmptyString); - m_choicePadShape->SetSelection(0); - m_txtPadWidth->SetValue(wxEmptyString); - m_txtPadLength->SetValue(wxEmptyString); - m_txtPitch->SetValue(wxEmptyString); - m_txtPadSpanX->SetValue(wxEmptyString); - m_txtPadSpanY->SetValue(wxEmptyString); - m_txtDrillSize->SetValue(wxEmptyString); - m_txtAuxPadLength->SetValue(wxEmptyString); - m_txtAuxPadWidth->SetValue(wxEmptyString); - m_txtBodyLength->SetValue(wxEmptyString); - m_txtBodyWidth->SetValue(wxEmptyString); - m_txtRefLabel->SetValue(wxEmptyString); - m_chkRefLabelVisible->SetValue(false); - m_txtValueLabel->SetValue(wxEmptyString); - m_chkValueLabelVisible->SetValue(false); + m_txtPadCount->SetValue(wxEmptyString); + m_choicePadShape->SetSelection(0); + m_txtPadWidth->SetValue(wxEmptyString); + m_txtPadLength->SetValue(wxEmptyString); + m_txtPitch->SetValue(wxEmptyString); + m_txtPadSpanX->SetValue(wxEmptyString); + m_txtPadSpanY->SetValue(wxEmptyString); + m_txtDrillSize->SetValue(wxEmptyString); + m_txtAuxPadLength->SetValue(wxEmptyString); + m_txtAuxPadWidth->SetValue(wxEmptyString); + m_txtBodyLength->SetValue(wxEmptyString); + m_txtBodyWidth->SetValue(wxEmptyString); + m_txtRefLabel->SetValue(wxEmptyString); + m_chkRefLabelVisible->SetValue(false); + m_txtValueLabel->SetValue(wxEmptyString); + m_chkValueLabelVisible->SetValue(false); m_choiceShape->SetSelection(0); m_txtShapeHeight->SetValue(wxEmptyString); - m_txtPadCount->SetEditable(false); - m_choicePadShape->Enable(false); - m_txtPadWidth->SetEditable(false); - m_txtPadLength->SetEditable(false); - m_txtPitch->SetEditable(false); - m_txtPadSpanX->SetEditable(false); - m_txtPadSpanY->SetEditable(false); - m_txtDrillSize->SetEditable(false); - m_txtAuxPadLength->SetEditable(false); - m_txtAuxPadWidth->SetEditable(false); - m_txtBodyLength->SetEditable(false); - m_txtBodyWidth->SetEditable(false); - m_txtRefLabel->SetEditable(false); - m_chkRefLabelVisible->Enable(false); - m_txtValueLabel->SetEditable(false); - m_chkValueLabelVisible->Enable(false); + m_txtPadCount->SetEditable(false); + m_choicePadShape->Enable(false); + m_txtPadWidth->SetEditable(false); + m_txtPadLength->SetEditable(false); + m_txtPitch->SetEditable(false); + m_txtPadSpanX->SetEditable(false); + m_txtPadSpanY->SetEditable(false); + m_txtDrillSize->SetEditable(false); + m_txtAuxPadLength->SetEditable(false); + m_txtAuxPadWidth->SetEditable(false); + m_txtBodyLength->SetEditable(false); + m_txtBodyWidth->SetEditable(false); + m_txtRefLabel->SetEditable(false); + m_chkRefLabelVisible->Enable(false); + m_txtValueLabel->SetEditable(false); + m_chkValueLabelVisible->Enable(false); m_choiceShape->Enable(false); m_txtShapeHeight->SetEditable(false); - m_txtPadCount->SetBackgroundColour(PROTECTED); - m_choicePadShape->SetBackgroundColour(wxNullColour); - m_txtPadWidth->SetBackgroundColour(PROTECTED); - m_txtPadLength->SetBackgroundColour(PROTECTED); - m_txtPitch->SetBackgroundColour(PROTECTED); - m_txtPadSpanX->SetBackgroundColour(PROTECTED); - m_txtPadSpanY->SetBackgroundColour(PROTECTED); - m_txtDrillSize->SetBackgroundColour(PROTECTED); - m_txtAuxPadLength->SetBackgroundColour(PROTECTED); - m_txtAuxPadWidth->SetBackgroundColour(PROTECTED); - m_txtBodyLength->SetBackgroundColour(PROTECTED); - m_txtBodyWidth->SetBackgroundColour(PROTECTED); - m_txtRefLabel->SetBackgroundColour(PROTECTED); - m_chkRefLabelVisible->SetBackgroundColour(wxNullColour); - m_txtValueLabel->SetBackgroundColour(PROTECTED); - m_chkValueLabelVisible->SetBackgroundColour(wxNullColour); - m_choiceShape->SetBackgroundColour(wxNullColour); - m_txtShapeHeight->SetBackgroundColour(PROTECTED); - } - - m_btnSavePart->Enable(false); - m_btnRevertPart->Enable(false); - - if (PartData[fp].Count() == 0) - return; - bool DefEnable = !CompareMode && !FromRepository[fp]; - wxString templatename = GetTemplateName(PartData[fp]); - - wxString field = GetDescription(PartData[fp], SymbolMode); - m_txtDescription->SetValue(field); - m_txtDescription->SetToolTip(field); - m_txtDescription->SetEditable(DefEnable); - m_txtDescription->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); - - if (SymbolMode) { - /* schematic mode */ - - field = GetAliases(PartData[fp]); - m_txtAlias->SetValue(field); - m_txtAlias->SetEditable(DefEnable); - m_txtAlias->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); - - field = GetFootprints(PartData[fp]); - m_txtFootprintFilter->SetValue(field); - m_txtFootprintFilter->SetEditable(DefEnable); - m_txtFootprintFilter->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); - - m_txtPadCount->SetValue(wxString::Format(wxT("%d"), PinDataCount[fp])); - bool enable = templatename.length() > 0 && DefEnable; - if (enable) { - /* check whether the template allows multiple pin counts (many 2-pin - components only allow 2 pins) */ - field = GetTemplateHeaderField(templatename, wxT("pins"), SymbolMode); - if (field.length() > 0 && field.Find(wxT(' ')) < 0) - enable = false; /* since leading and trailing white-space was already - trimmed, when more white-space exists, it must be as - a separator */ - } - m_txtPadCount->SetEditable(enable); - m_txtPadCount->SetBackgroundColour(enable ? ENABLED : PROTECTED); - - if (m_gridPinNames->GetNumberRows() > 0) - m_gridPinNames->DeleteRows(0, m_gridPinNames->GetNumberRows()); - m_gridPinNames->InsertRows(0, PinDataCount[fp]); - m_gridPinNames->EnableEditing(true); - for (int idx = 0; idx < PinDataCount[fp]; idx++) { - wxString field = PinData[fp][idx].name; - if ( PinData[fp][idx].part > 0) - field = wxString::Format(wxT("%d:"), PinData[fp][idx].part) + field; - m_gridPinNames->SetCellValue((int)idx, 0, PinData[fp][idx].number); - m_gridPinNames->SetCellValue((int)idx, 1, field); - m_gridPinNames->SetCellValue((int)idx, 2, PinTypeNames[PinData[fp][idx].type]); - m_gridPinNames->SetCellValue((int)idx, 3, PinShapeNames[PinData[fp][idx].shape]); - m_gridPinNames->SetCellValue((int)idx, 4, GetPinSectionName(0, PinData[fp][idx].section)); - bool enable = templatename.length() > 0 && DefEnable; - m_gridPinNames->SetReadOnly(idx, 0, !DefEnable); - m_gridPinNames->SetReadOnly(idx, 1, !DefEnable); - m_gridPinNames->SetReadOnly(idx, 2, !DefEnable); - m_gridPinNames->SetReadOnly(idx, 3, !DefEnable); - m_gridPinNames->SetReadOnly(idx, 4, !enable); - m_gridPinNames->SetCellBackgroundColour(idx, 0, DefEnable ? ENABLED : PROTECTED); - m_gridPinNames->SetCellBackgroundColour(idx, 1, DefEnable ? ENABLED : PROTECTED); - m_gridPinNames->SetCellBackgroundColour(idx, 2, DefEnable ? ENABLED : PROTECTED); - m_gridPinNames->SetCellBackgroundColour(idx, 3, DefEnable ? ENABLED : PROTECTED); - m_gridPinNames->SetCellBackgroundColour(idx, 4, enable ? ENABLED : PROTECTED); - if (DefEnable) { - m_gridPinNames->SetCellEditor(idx, 2, new wxGridCellChoiceEditor(sizearray(PinTypeNames), PinTypeNames)); - m_gridPinNames->SetCellEditor(idx, 3, new wxGridCellChoiceEditor(sizearray(PinShapeNames) - 1, PinShapeNames)); - } - if (enable) { - wxArrayString list; - for (int i = 0; i < PinInfo::SectionCount; i++) { - wxString name = GetPinSectionName(0, i); - if (name.Length() > 0) - list.Add(name); - } - m_gridPinNames->SetCellEditor(idx, 4, new wxGridCellChoiceEditor(list)); - } - } - if (PinDataCount[fp] > 0) { - #if defined _WIN32 - m_gridPinNames->SetColLabelSize(16); //??? should read this from a user-setting - #else - m_gridPinNames->SetColLabelSize(20); - #endif - } - m_gridPinNames->AutoSizeColumn(0); - m_gridPinNames->AutoSizeColumn(1); - m_gridPinNames->AutoSizeColumn(2); - m_gridPinNames->AutoSizeColumn(3); - m_gridPinNames->AutoSizeColumn(4); - wxSizer* sizer = m_gridPinNames->GetContainingSizer(); - wxASSERT(sizer != 0); - sizer->Layout(); - m_panelSettings->FitInside(); /* force recalculation of the panel (calling layout is not enough) */ - - } else { - /* footprint mode */ - - field = GetKeywords(PartData[fp], SymbolMode); - m_txtAlias->SetValue(field); - m_txtAlias->SetEditable(DefEnable); - m_txtAlias->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); - - m_txtPadCount->SetValue(wxString::Format(wxT("%d"), Footprint[fp].PadCount)); - bool enable = templatename.length() > 0 && DefEnable; - if (enable) { - /* check whether the template allows multiple pin counts (many 2-pin - components only allow 2 pins) */ - field = GetTemplateHeaderField(templatename, wxT("pins"), SymbolMode); - if (field.length() == 0 || field.Find(wxT(' ')) < 0) - enable = false; /* since leading and trailing white-space was already - trimmed, when more white-space exists, it must be as - a separator */ - } - m_txtPadCount->SetEditable(enable); - m_txtPadCount->SetBackgroundColour(enable ? ENABLED : PROTECTED); - - enable = DefEnable; - int idx; - switch (Footprint[fp].PadShape) { - case 'C': - idx = m_choicePadShape->FindString(wxT("Round")); - break; - case 'O': - idx = m_choicePadShape->FindString(wxT("Obround")); - break; - case 'R': - idx = m_choicePadShape->FindString(wxT("Rectangular")); - break; - case 'S': - idx = m_choicePadShape->FindString(wxT("Round + square")); - break; - case 'T': - idx = m_choicePadShape->FindString(wxT("Trapezoid")); - break; - default: - idx = m_choicePadShape->FindString(wxT("(varies)")); - enable = false; - } - wxASSERT(idx >= 0); - m_choicePadShape->SetSelection(idx); - m_choicePadShape->Enable(enable); - m_choicePadShape->SetBackgroundColour(enable ? ENABLED : PROTECTED); - - const CoordPair& padsize = Footprint[fp].PadSize[0]; - if (padsize.GetX() > EPSILON) { - m_txtPadWidth->SetValue(wxString::Format(wxT("%.3f"), padsize.GetX())); - m_txtPadWidth->SetEditable(DefEnable); - m_txtPadWidth->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); - } - if (padsize.GetY() > EPSILON) { - m_txtPadLength->SetValue(wxString::Format(wxT("%.3f"), padsize.GetY())); - m_txtPadLength->SetEditable(DefEnable); - m_txtPadLength->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); - } - - const CoordPair& auxpadsize = Footprint[fp].PadSize[1]; - if (auxpadsize.GetX() > EPSILON) { - m_txtAuxPadWidth->SetValue(wxString::Format(wxT("%.3f"), auxpadsize.GetX())); - m_txtAuxPadWidth->SetEditable(DefEnable); - m_txtAuxPadWidth->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); - } - if (auxpadsize.GetY() > EPSILON) { - m_txtAuxPadLength->SetValue(wxString::Format(wxT("%.3f"), auxpadsize.GetY())); - m_txtAuxPadLength->SetEditable(DefEnable); - m_txtAuxPadLength->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); - } - - if (Footprint[fp].Pitch > EPSILON) { - m_txtPitch->SetValue(wxString::Format(wxT("%.3f"), Footprint[fp].Pitch)); - enable = DefEnable && Footprint[fp].RegPadCount > 0 - && Footprint[fp].PadLines > 0 - && Footprint[fp].OriginCentred; - m_txtPitch->SetEditable(enable); - m_txtPitch->SetBackgroundColour(enable ? ENABLED : PROTECTED); - } - - if (Footprint[fp].SpanHor > EPSILON) { - m_txtPadSpanX->SetValue(wxString::Format(wxT("%.3f"), Footprint[fp].SpanHor)); - m_txtPadSpanX->SetEditable(DefEnable); - m_txtPadSpanX->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); - } - if (Footprint[fp].SpanVer > EPSILON) { - m_txtPadSpanY->SetValue(wxString::Format(wxT("%.3f"), Footprint[fp].SpanVer)); - m_txtPadSpanY->SetEditable(DefEnable); - m_txtPadSpanY->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); - } - - if (Footprint[fp].DrillSize > EPSILON) { - m_txtDrillSize->SetValue(wxString::Format(wxT("%.3f"), Footprint[fp].DrillSize)); - m_txtDrillSize->SetEditable(DefEnable); - m_txtDrillSize->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); - } - - if (templatename.length() > 0) { + m_txtPadCount->SetBackgroundColour(PROTECTED); + m_choicePadShape->SetBackgroundColour(wxNullColour); + m_txtPadWidth->SetBackgroundColour(PROTECTED); + m_txtPadLength->SetBackgroundColour(PROTECTED); + m_txtPitch->SetBackgroundColour(PROTECTED); + m_txtPadSpanX->SetBackgroundColour(PROTECTED); + m_txtPadSpanY->SetBackgroundColour(PROTECTED); + m_txtDrillSize->SetBackgroundColour(PROTECTED); + m_txtAuxPadLength->SetBackgroundColour(PROTECTED); + m_txtAuxPadWidth->SetBackgroundColour(PROTECTED); + m_txtBodyLength->SetBackgroundColour(PROTECTED); + m_txtBodyWidth->SetBackgroundColour(PROTECTED); + m_txtRefLabel->SetBackgroundColour(PROTECTED); + m_chkRefLabelVisible->SetBackgroundColour(wxNullColour); + m_txtValueLabel->SetBackgroundColour(PROTECTED); + m_chkValueLabelVisible->SetBackgroundColour(wxNullColour); + m_choiceShape->SetBackgroundColour(wxNullColour); + m_txtShapeHeight->SetBackgroundColour(PROTECTED); + } + + m_btnSavePart->Enable(false); + m_btnRevertPart->Enable(false); + + if (PartData[fp].Count() == 0) + return; + bool DefEnable = !CompareMode && !FromRepository[fp]; + wxString templatename = GetTemplateName(PartData[fp]); + + wxString field = GetDescription(PartData[fp], SymbolMode); + m_txtDescription->SetValue(field); + m_txtDescription->SetToolTip(field); + m_txtDescription->SetEditable(DefEnable); + m_txtDescription->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); + + if (SymbolMode) { + /* schematic mode */ + + field = GetAliases(PartData[fp]); + m_txtAlias->SetValue(field); + m_txtAlias->SetEditable(DefEnable); + m_txtAlias->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); + + field = GetFootprints(PartData[fp]); + m_txtFootprintFilter->SetValue(field); + m_txtFootprintFilter->SetEditable(DefEnable); + m_txtFootprintFilter->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); + + m_txtPadCount->SetValue(wxString::Format(wxT("%d"), PinDataCount[fp])); + bool enable = templatename.length() > 0 && DefEnable; + if (enable) { + /* check whether the template allows multiple pin counts (many 2-pin + components only allow 2 pins) */ + field = GetTemplateHeaderField(templatename, wxT("pins"), SymbolMode); + if (field.length() > 0 && field.Find(wxT(' ')) < 0) + enable = false; /* since leading and trailing white-space was already + trimmed, when more white-space exists, it must be as + a separator */ + } + m_txtPadCount->SetEditable(enable); + m_txtPadCount->SetBackgroundColour(enable ? ENABLED : PROTECTED); + + if (m_gridPinNames->GetNumberRows() > 0) + m_gridPinNames->DeleteRows(0, m_gridPinNames->GetNumberRows()); + m_gridPinNames->InsertRows(0, PinDataCount[fp]); + m_gridPinNames->EnableEditing(true); + for (int idx = 0; idx < PinDataCount[fp]; idx++) { + wxString field = PinData[fp][idx].name; + if ( PinData[fp][idx].part > 0) + field = wxString::Format(wxT("%d:"), PinData[fp][idx].part) + field; + m_gridPinNames->SetCellValue((int)idx, 0, PinData[fp][idx].number); + m_gridPinNames->SetCellValue((int)idx, 1, field); + m_gridPinNames->SetCellValue((int)idx, 2, PinTypeNames[PinData[fp][idx].type]); + m_gridPinNames->SetCellValue((int)idx, 3, PinShapeNames[PinData[fp][idx].shape]); + m_gridPinNames->SetCellValue((int)idx, 4, GetPinSectionName(0, PinData[fp][idx].section)); + bool enable = templatename.length() > 0 && DefEnable; + m_gridPinNames->SetReadOnly(idx, 0, !DefEnable); + m_gridPinNames->SetReadOnly(idx, 1, !DefEnable); + m_gridPinNames->SetReadOnly(idx, 2, !DefEnable); + m_gridPinNames->SetReadOnly(idx, 3, !DefEnable); + m_gridPinNames->SetReadOnly(idx, 4, !enable); + m_gridPinNames->SetCellBackgroundColour(idx, 0, DefEnable ? ENABLED : PROTECTED); + m_gridPinNames->SetCellBackgroundColour(idx, 1, DefEnable ? ENABLED : PROTECTED); + m_gridPinNames->SetCellBackgroundColour(idx, 2, DefEnable ? ENABLED : PROTECTED); + m_gridPinNames->SetCellBackgroundColour(idx, 3, DefEnable ? ENABLED : PROTECTED); + m_gridPinNames->SetCellBackgroundColour(idx, 4, enable ? ENABLED : PROTECTED); + if (DefEnable) { + m_gridPinNames->SetCellEditor(idx, 2, new wxGridCellChoiceEditor(sizearray(PinTypeNames), PinTypeNames)); + m_gridPinNames->SetCellEditor(idx, 3, new wxGridCellChoiceEditor(sizearray(PinShapeNames) - 1, PinShapeNames)); + } + if (enable) { + wxArrayString list; + for (int i = 0; i < PinInfo::SectionCount; i++) { + wxString name = GetPinSectionName(0, i); + if (name.Length() > 0) + list.Add(name); + } + m_gridPinNames->SetCellEditor(idx, 4, new wxGridCellChoiceEditor(list)); + } + } + if (PinDataCount[fp] > 0) { + #if defined _WIN32 + m_gridPinNames->SetColLabelSize(16); //??? should read this from a user-setting + #else + m_gridPinNames->SetColLabelSize(20); + #endif + } + m_gridPinNames->AutoSizeColumn(0); + m_gridPinNames->AutoSizeColumn(1); + m_gridPinNames->AutoSizeColumn(2); + m_gridPinNames->AutoSizeColumn(3); + m_gridPinNames->AutoSizeColumn(4); + wxSizer* sizer = m_gridPinNames->GetContainingSizer(); + wxASSERT(sizer != 0); + sizer->Layout(); + m_panelSettings->FitInside(); /* force recalculation of the panel (calling layout is not enough) */ + + } else { + /* footprint mode */ + + field = GetKeywords(PartData[fp], SymbolMode); + m_txtAlias->SetValue(field); + m_txtAlias->SetEditable(DefEnable); + m_txtAlias->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); + + m_txtPadCount->SetValue(wxString::Format(wxT("%d"), Footprint[fp].PadCount)); + bool enable = templatename.length() > 0 && DefEnable; + if (enable) { + /* check whether the template allows multiple pin counts (many 2-pin + components only allow 2 pins) */ + field = GetTemplateHeaderField(templatename, wxT("pins"), SymbolMode); + if (field.length() == 0 || field.Find(wxT(' ')) < 0) + enable = false; /* since leading and trailing white-space was already + trimmed, when more white-space exists, it must be as + a separator */ + } + m_txtPadCount->SetEditable(enable); + m_txtPadCount->SetBackgroundColour(enable ? ENABLED : PROTECTED); + + enable = DefEnable; + int idx; + switch (Footprint[fp].PadShape) { + case 'C': + idx = m_choicePadShape->FindString(wxT("Round")); + break; + case 'O': + idx = m_choicePadShape->FindString(wxT("Obround")); + break; + case 'R': + idx = m_choicePadShape->FindString(wxT("Rectangular")); + break; + case 'S': + idx = m_choicePadShape->FindString(wxT("Round + square")); + break; + case 'T': + idx = m_choicePadShape->FindString(wxT("Trapezoid")); + break; + default: + idx = m_choicePadShape->FindString(wxT("(varies)")); + enable = false; + } + wxASSERT(idx >= 0); + m_choicePadShape->SetSelection(idx); + m_choicePadShape->Enable(enable); + m_choicePadShape->SetBackgroundColour(enable ? ENABLED : PROTECTED); + + const CoordPair& padsize = Footprint[fp].PadSize[0]; + if (padsize.GetX() > EPSILON) { + m_txtPadWidth->SetValue(wxString::Format(wxT("%.3f"), padsize.GetX())); + m_txtPadWidth->SetEditable(DefEnable); + m_txtPadWidth->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); + } + if (padsize.GetY() > EPSILON) { + m_txtPadLength->SetValue(wxString::Format(wxT("%.3f"), padsize.GetY())); + m_txtPadLength->SetEditable(DefEnable); + m_txtPadLength->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); + } + + const CoordPair& auxpadsize = Footprint[fp].PadSize[1]; + if (auxpadsize.GetX() > EPSILON) { + m_txtAuxPadWidth->SetValue(wxString::Format(wxT("%.3f"), auxpadsize.GetX())); + m_txtAuxPadWidth->SetEditable(DefEnable); + m_txtAuxPadWidth->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); + } + if (auxpadsize.GetY() > EPSILON) { + m_txtAuxPadLength->SetValue(wxString::Format(wxT("%.3f"), auxpadsize.GetY())); + m_txtAuxPadLength->SetEditable(DefEnable); + m_txtAuxPadLength->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); + } + + if (Footprint[fp].Pitch > EPSILON) { + m_txtPitch->SetValue(wxString::Format(wxT("%.3f"), Footprint[fp].Pitch)); + enable = DefEnable && Footprint[fp].RegPadCount > 0 + && Footprint[fp].PadLines > 0 + && Footprint[fp].OriginCentred; + m_txtPitch->SetEditable(enable); + m_txtPitch->SetBackgroundColour(enable ? ENABLED : PROTECTED); + } + + if (Footprint[fp].SpanHor > EPSILON) { + m_txtPadSpanX->SetValue(wxString::Format(wxT("%.3f"), Footprint[fp].SpanHor)); + m_txtPadSpanX->SetEditable(DefEnable); + m_txtPadSpanX->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); + } + if (Footprint[fp].SpanVer > EPSILON) { + m_txtPadSpanY->SetValue(wxString::Format(wxT("%.3f"), Footprint[fp].SpanVer)); + m_txtPadSpanY->SetEditable(DefEnable); + m_txtPadSpanY->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); + } + + if (Footprint[fp].DrillSize > EPSILON) { + m_txtDrillSize->SetValue(wxString::Format(wxT("%.3f"), Footprint[fp].DrillSize)); + m_txtDrillSize->SetEditable(DefEnable); + m_txtDrillSize->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); + } + + if (templatename.length() > 0) { /* fill the 3D model list */ - field = GetTemplateHeaderField(templatename, wxT("model"), SymbolMode); + field = GetTemplateHeaderField(templatename, wxT("model"), SymbolMode); wxArrayString models = wxSplit(field, wxT(' ')); m_choiceShape->Set(models); /* check which library the part comes from */ wxString library, author; if (fp == 1) { wxString modname = GetSelection(m_listModulesRight, m_choiceModuleRight, &library, &author); - wxASSERT(!modname.IsEmpty()); + wxASSERT(!modname.IsEmpty()); } else { - wxString leftmod = GetSelection(m_listModulesLeft, m_choiceModuleLeft, &library, &author); - wxString rightmod = GetSelection(m_listModulesRight, m_choiceModuleRight, &library, &author); + wxString leftmod = GetSelection(m_listModulesLeft, m_choiceModuleLeft, &library, &author); + wxString rightmod = GetSelection(m_listModulesRight, m_choiceModuleRight, &library, &author); wxASSERT(leftmod.IsEmpty() || rightmod.IsEmpty()); } int idx = 0; @@ -6942,49 +6943,49 @@ void libmngrFrame::UpdateDetails(int fp) if (params.Count() >= 2) m_txtShapeHeight->SetValue(params[1]); } - m_txtShapeHeight->SetEditable(DefEnable); - m_txtShapeHeight->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); + m_txtShapeHeight->SetEditable(DefEnable); + m_txtShapeHeight->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); } m_choiceShape->SetSelection(idx); enable = (DefEnable && models.Count() > 1); m_choiceShape->Enable(enable); m_choiceShape->SetBackgroundColour(enable ? ENABLED : PROTECTED); - } - } - - /* check whether a body size is specified as a default parameter; if not, keep - the body size disabled (width & length separately) */ - bool setwidth = false; - bool setlength = false; - if (templatename.length() > 0) { - field = GetTemplateHeaderField(templatename, wxT("param"), SymbolMode); - setwidth = (field.Find(wxT("@BW")) >= 0); - setlength = (field.Find(wxT("@BL")) >= 0); - } - if (BodySize[fp].BodyLength > EPSILON) { - m_txtBodyLength->SetValue(wxString::Format(wxT("%.3f"), BodySize[fp].BodyLength)); - bool enable = setlength && DefEnable; - m_txtBodyLength->SetEditable(enable); - m_txtBodyLength->SetBackgroundColour(enable ? ENABLED : PROTECTED); - } - if (BodySize[fp].BodyWidth > EPSILON) { - m_txtBodyWidth->SetValue(wxString::Format(wxT("%.3f"), BodySize[fp].BodyWidth)); - bool enable = setwidth && DefEnable; - m_txtBodyWidth->SetEditable(enable); - m_txtBodyWidth->SetBackgroundColour(enable ? ENABLED : PROTECTED); - } - - m_txtRefLabel->SetValue(wxString::Format(wxT("%.2f"), LabelData[fp].RefLabelSize)); - m_txtRefLabel->SetEditable(DefEnable); - m_txtRefLabel->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); - m_chkRefLabelVisible->SetValue(LabelData[fp].RefLabelVisible); - m_chkRefLabelVisible->Enable(DefEnable); - - m_txtValueLabel->SetValue(wxString::Format(wxT("%.2f"), LabelData[fp].ValueLabelSize)); - m_txtValueLabel->SetEditable(DefEnable); - m_txtValueLabel->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); - m_chkValueLabelVisible->SetValue(LabelData[fp].ValueLabelVisible); - m_chkValueLabelVisible->Enable(DefEnable); - - FieldEdited = false; /* clear this flag for all implicit changes */ + } + } + + /* check whether a body size is specified as a default parameter; if not, keep + the body size disabled (width & length separately) */ + bool setwidth = false; + bool setlength = false; + if (templatename.length() > 0) { + field = GetTemplateHeaderField(templatename, wxT("param"), SymbolMode); + setwidth = (field.Find(wxT("@BW")) >= 0); + setlength = (field.Find(wxT("@BL")) >= 0); + } + if (BodySize[fp].BodyLength > EPSILON) { + m_txtBodyLength->SetValue(wxString::Format(wxT("%.3f"), BodySize[fp].BodyLength)); + bool enable = setlength && DefEnable; + m_txtBodyLength->SetEditable(enable); + m_txtBodyLength->SetBackgroundColour(enable ? ENABLED : PROTECTED); + } + if (BodySize[fp].BodyWidth > EPSILON) { + m_txtBodyWidth->SetValue(wxString::Format(wxT("%.3f"), BodySize[fp].BodyWidth)); + bool enable = setwidth && DefEnable; + m_txtBodyWidth->SetEditable(enable); + m_txtBodyWidth->SetBackgroundColour(enable ? ENABLED : PROTECTED); + } + + m_txtRefLabel->SetValue(wxString::Format(wxT("%.2f"), LabelData[fp].RefLabelSize)); + m_txtRefLabel->SetEditable(DefEnable); + m_txtRefLabel->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); + m_chkRefLabelVisible->SetValue(LabelData[fp].RefLabelVisible); + m_chkRefLabelVisible->Enable(DefEnable); + + m_txtValueLabel->SetValue(wxString::Format(wxT("%.2f"), LabelData[fp].ValueLabelSize)); + m_txtValueLabel->SetEditable(DefEnable); + m_txtValueLabel->SetBackgroundColour(DefEnable ? ENABLED : PROTECTED); + m_chkValueLabelVisible->SetValue(LabelData[fp].ValueLabelVisible); + m_chkValueLabelVisible->Enable(DefEnable); + + FieldEdited = false; /* clear this flag for all implicit changes */ } \ No newline at end of file diff --git a/src/libraryfunctions.cpp b/src/libraryfunctions.cpp index 6b5aaad..0e72121 100644 --- a/src/libraryfunctions.cpp +++ b/src/libraryfunctions.cpp @@ -16,7 +16,7 @@ * License for the specific language governing permissions and limitations * under the License. * - * $Id: libraryfunctions.cpp 5685 2017-05-23 10:35:40Z thiadmer $ + * $Id: libraryfunctions.cpp 5686 2017-05-24 13:56:46Z thiadmer $ */ #include @@ -30,18 +30,18 @@ #include "librarymanager.h" #include "libraryfunctions.h" #if !defined NO_CURL - #include "remotelink.h" + #include "remotelink.h" #endif -#define EoC '\x1a' /* special "end-of-comment" character */ -#define MM(d) (d) -#define MIL10(d) (long)floor(d / 0.00254 + 0.5) +#define EoC '\x1a' /* special "end-of-comment" character */ +#define MM(d) (d) +#define MIL10(d) (long)floor(d / 0.00254 + 0.5) #if !defined sizearray - #define sizearray(a) (sizeof(a) / sizeof((a)[0])) + #define sizearray(a) (sizeof(a) / sizeof((a)[0])) #endif #if !defined min - #define min(a, b) ((a) < (b) ? (a) : (b)) + #define min(a, b) ((a) < (b) ? (a) : (b)) #endif #include @@ -51,109 +51,109 @@ WX_DEFINE_OBJARRAY(ArrayCoordSize); /* a syntax changed for version 2.9 and higher; to also (still) support wxWidgets 2.8, a helper function is conditionally compiled */ #if wxCHECK_VERSION(2, 9, 0) - inline void str_replace(wxString& string, size_t start, size_t length, const wxString& sub) - { - string.replace(start, length, sub); - } + inline void str_replace(wxString& string, size_t start, size_t length, const wxString& sub) + { + string.replace(start, length, sub); + } #else - inline void str_replace(wxString& string, size_t start, size_t length, const wxString& sub) - { - string.replace(start, length, sub.c_str()); - } + inline void str_replace(wxString& string, size_t start, size_t length, const wxString& sub) + { + string.replace(start, length, sub.c_str()); + } #endif /* strips trailing zeros from a number; the input string should only contain a number */ static void StripTrailingZeros(wxString* string) { - /* if there is no decimal period, we are done quickly */ - if (string->Find(wxT('.'), true) < 0) - return; - int l = (int)string->length(); - wxASSERT(l > 0); /* must be, because we found a period */ - while ((*string)[l - 1] == wxT('0')) - l -= 1; - wxASSERT(l > 0); /* must be, because we would drop in the period eventually */ - if ((*string)[l - 1] == wxT('.')) - l -= 1; - if (l > 0) - *string = string->Left(l); - else - *string = wxT("0"); /* this can only occur if the input is ".000" */ + /* if there is no decimal period, we are done quickly */ + if (string->Find(wxT('.'), true) < 0) + return; + int l = (int)string->length(); + wxASSERT(l > 0); /* must be, because we found a period */ + while ((*string)[l - 1] == wxT('0')) + l -= 1; + wxASSERT(l > 0); /* must be, because we would drop in the period eventually */ + if ((*string)[l - 1] == wxT('.')) + l -= 1; + if (l > 0) + *string = string->Left(l); + else + *string = wxT("0"); /* this can only occur if the input is ".000" */ } wxString GetToken(wxString* string) { - if (string->length() == 0) - return wxEmptyString; - - wxString token; - int index; - bool stripquotes = false; - - if ((*string)[0] == wxT('"')) { - *string = string->Mid(1); - index = string->Find(wxT('"')); - stripquotes = true; - } else { - index = string->Find(wxT(' ')); - } - - if (index < 0) { - token = *string; - string->Clear(); - } else { - token = string->Left(index); - *string = string->Mid(index); - } - - if (stripquotes && (*string)[0] == wxT('"')) - *string = string->Mid(1); - string->Trim(false); /* remove leading white-space */ - - return token; + if (string->length() == 0) + return wxEmptyString; + + wxString token; + int index; + bool stripquotes = false; + + if ((*string)[0] == wxT('"')) { + *string = string->Mid(1); + index = string->Find(wxT('"')); + stripquotes = true; + } else { + index = string->Find(wxT(' ')); + } + + if (index < 0) { + token = *string; + string->Clear(); + } else { + token = string->Left(index); + *string = string->Mid(index); + } + + if (stripquotes && (*string)[0] == wxT('"')) + *string = string->Mid(1); + string->Trim(false); /* remove leading white-space */ + + return token; } long GetTokenLong(wxString* string) { - wxString token; - - int index = string->Find(wxT(' ')); - if (index < 0) { - token = *string; - string->Clear(); - } else { - token = string->Left(index); - *string = string->Mid(index); - string->Trim(false); /* remove leading white-space */ - } - - long val; - if (!token.ToLong(&val)) - val = 0; - return val; + wxString token; + + int index = string->Find(wxT(' ')); + if (index < 0) { + token = *string; + string->Clear(); + } else { + token = string->Left(index); + *string = string->Mid(index); + string->Trim(false); /* remove leading white-space */ + } + + long val; + if (!token.ToLong(&val)) + val = 0; + return val; } /** GetTokenDouble() returns a floating-point value in mm. */ double GetTokenDouble(wxString* string) { - wxString token; - - int index = string->Find(wxT(' ')); - if (index < 0) { - token = *string; - string->Clear(); - } else { - token = string->Left(index); - *string = string->Mid(index); - string->Trim(false); /* remove leading white-space */ - } - - double val; - if (!token.ToDouble(&val)) - val = 0; - return val; + wxString token; + + int index = string->Find(wxT(' ')); + if (index < 0) { + token = *string; + string->Clear(); + } else { + token = string->Left(index); + *string = string->Mid(index); + string->Trim(false); /* remove leading white-space */ + } + + double val; + if (!token.ToDouble(&val)) + val = 0; + return val; } /** GetTokenDim() returns a value in mm. If the library is in decimil format, @@ -161,165 +161,165 @@ double GetTokenDouble(wxString* string) */ double GetTokenDim(wxString* string, bool unit_mm) { - wxString token; - - int index = string->Find(wxT(' ')); - if (index < 0) { - token = *string; - string->Clear(); - } else { - token = string->Left(index); - *string = string->Mid(index); - string->Trim(false); /* remove leading white-space */ - } - - double val; - if (unit_mm) { - /* the value is in floating point */ - token.ToDouble(&val); - } else { - long t; - token.ToLong(&t); - val = (double)t * 0.00254; - } - return val; + wxString token; + + int index = string->Find(wxT(' ')); + if (index < 0) { + token = *string; + string->Clear(); + } else { + token = string->Left(index); + *string = string->Mid(index); + string->Trim(false); /* remove leading white-space */ + } + + double val; + if (unit_mm) { + /* the value is in floating point */ + token.ToDouble(&val); + } else { + long t; + token.ToLong(&t); + val = (double)t * 0.00254; + } + return val; } /** GetSection() gets a subsection of an s-expression in the string, that - * starts with the token. It returns the parameters of the section, without - * the parentheses and without the token name. - * The token parameter should not include the opening parenthesis. + * starts with the token. It returns the parameters of the section, without + * the parentheses and without the token name. + * The token parameter should not include the opening parenthesis. */ wxString GetSection(const wxString& string, const wxString& token, int skip) { - wxASSERT(token[0] != wxT('(')); - size_t tokenlen = token.length(); - int level = 0; - bool instring = false; - unsigned pos; - for (pos = 0; pos < string.length(); pos++) { - if (string[pos] == wxT('(') && !instring && level == 0) { - wxString word = string.Mid(pos + 1, tokenlen); - if (word.CmpNoCase(token) == 0 && string[pos + tokenlen + 1] == wxT(' ')) { - if (skip == 0) - break; - skip--; - } - } - if (string[pos] == wxT('(') && !instring) - level++; - else if (string[pos] == wxT(')') && !instring) - level--; - else if (string[pos] == wxT('"')) - instring = !instring; - else if (string[pos] == wxT('\\') && string[pos] == wxT('"')) - pos++; /* skip both \ and " */ - } - if (pos >= (int)string.length()) - return wxEmptyString; - wxASSERT(string[pos] == wxT('(')); - pos += (int)token.length() + 1; /* +1 for the '(' */ - wxASSERT(string[pos] == wxT(' ')); - level = 0; - instring = false; - unsigned idx; - for (idx = pos; idx < string.length() && level >= 0; idx++) { - if (string[idx] == wxT('(') && !instring) - level++; - else if (string[idx] == wxT(')') && !instring) - level--; - else if (string[idx] == wxT('"')) - instring = !instring; - else if (string[idx] == wxT('\\') && string[idx] == wxT('"')) - idx++; /* skip both \ and " */ - } - wxString params = string.Mid(pos, idx - pos - 1); - params.Trim(false); - params.Trim(true); - return params; + wxASSERT(token[0] != wxT('(')); + size_t tokenlen = token.length(); + int level = 0; + bool instring = false; + unsigned pos; + for (pos = 0; pos < string.length(); pos++) { + if (string[pos] == wxT('(') && !instring && level == 0) { + wxString word = string.Mid(pos + 1, tokenlen); + if (word.CmpNoCase(token) == 0 && string[pos + tokenlen + 1] == wxT(' ')) { + if (skip == 0) + break; + skip--; + } + } + if (string[pos] == wxT('(') && !instring) + level++; + else if (string[pos] == wxT(')') && !instring) + level--; + else if (string[pos] == wxT('"')) + instring = !instring; + else if (string[pos] == wxT('\\') && string[pos] == wxT('"')) + pos++; /* skip both \ and " */ + } + if (pos >= (int)string.length()) + return wxEmptyString; + wxASSERT(string[pos] == wxT('(')); + pos += (int)token.length() + 1; /* +1 for the '(' */ + wxASSERT(string[pos] == wxT(' ')); + level = 0; + instring = false; + unsigned idx; + for (idx = pos; idx < string.length() && level >= 0; idx++) { + if (string[idx] == wxT('(') && !instring) + level++; + else if (string[idx] == wxT(')') && !instring) + level--; + else if (string[idx] == wxT('"')) + instring = !instring; + else if (string[idx] == wxT('\\') && string[idx] == wxT('"')) + idx++; /* skip both \ and " */ + } + wxString params = string.Mid(pos, idx - pos - 1); + params.Trim(false); + params.Trim(true); + return params; } /** SetSection() replaces the parameters in a section of an s-expression. - * The token parameter should not include the opening parenthesis. + * The token parameter should not include the opening parenthesis. */ bool SetSection(wxString& string, const wxString& token, const wxString& params) { - wxASSERT(token[0] != wxT('(')); - int pos = string.Find(wxT("(") + token + wxT(" ")); - if (pos < 0) - return false; - wxASSERT(pos < (int)string.length()); - wxASSERT(string[pos] == wxT('(')); - pos += (int)token.length() + 1; /* +1 for the '(' */ - wxASSERT(string[pos] == wxT(' ')); - while (pos < (int)string.length() && string[pos] == wxT(' ')) - pos++; - bool instring = false; - int level = 0; - unsigned idx; - for (idx = pos; idx < string.length() && level >= 0; idx++) { - if (string[idx] == wxT('(') && !instring) - level++; - else if (string[idx] == wxT(')') && !instring) - level--; - else if (string[idx] == wxT('"')) - instring = !instring; - else if (string[idx] == wxT('\\') && string[idx] == wxT('"')) - idx++; /* skip both \ and " */ - } - string = string.erase(pos, idx - pos - 1); - string = string.insert(pos, params); - return true; + wxASSERT(token[0] != wxT('(')); + int pos = string.Find(wxT("(") + token + wxT(" ")); + if (pos < 0) + return false; + wxASSERT(pos < (int)string.length()); + wxASSERT(string[pos] == wxT('(')); + pos += (int)token.length() + 1; /* +1 for the '(' */ + wxASSERT(string[pos] == wxT(' ')); + while (pos < (int)string.length() && string[pos] == wxT(' ')) + pos++; + bool instring = false; + int level = 0; + unsigned idx; + for (idx = pos; idx < string.length() && level >= 0; idx++) { + if (string[idx] == wxT('(') && !instring) + level++; + else if (string[idx] == wxT(')') && !instring) + level--; + else if (string[idx] == wxT('"')) + instring = !instring; + else if (string[idx] == wxT('\\') && string[idx] == wxT('"')) + idx++; /* skip both \ and " */ + } + string = string.erase(pos, idx - pos - 1); + string = string.insert(pos, params); + return true; } /** DeleteSection() removes a section in an s-expression. - * The token parameter should not include the opening parenthesis. + * The token parameter should not include the opening parenthesis. */ bool DeleteSection(wxString& string, const wxString& token) { - wxASSERT(token[0] != wxT('(')); - int pos = string.Find(wxT("(") + token + wxT(" ")); - if (pos < 0) - return false; - wxASSERT(pos < (int)string.length()); - wxASSERT(string[pos] == wxT('(')); - unsigned idx = pos + token.length() + 1; /* +1 for the '(' */ - wxASSERT(string[idx] == wxT(' ')); - while (idx < (int)string.length() && string[idx] == wxT(' ')) - idx++; - bool instring = false; - int level = 0; - while (idx < string.length() && level >= 0) { - if (string[idx] == wxT('(') && !instring) - level++; - else if (string[idx] == wxT(')') && !instring) - level--; - else if (string[idx] == wxT('"')) - instring = !instring; - else if (string[idx] == wxT('\\') && string[idx] == wxT('"')) - idx++; /* skip both \ and " */ + wxASSERT(token[0] != wxT('(')); + int pos = string.Find(wxT("(") + token + wxT(" ")); + if (pos < 0) + return false; + wxASSERT(pos < (int)string.length()); + wxASSERT(string[pos] == wxT('(')); + unsigned idx = pos + token.length() + 1; /* +1 for the '(' */ + wxASSERT(string[idx] == wxT(' ')); + while (idx < (int)string.length() && string[idx] == wxT(' ')) + idx++; + bool instring = false; + int level = 0; + while (idx < string.length() && level >= 0) { + if (string[idx] == wxT('(') && !instring) + level++; + else if (string[idx] == wxT(')') && !instring) + level--; + else if (string[idx] == wxT('"')) + instring = !instring; + else if (string[idx] == wxT('\\') && string[idx] == wxT('"')) + idx++; /* skip both \ and " */ idx++; - } - string = string.erase(pos, idx - pos - 1); - return true; + } + string = string.erase(pos, idx - pos - 1); + return true; } double NormalizeAngle(double angle) { - while (angle < 0.0) - angle += 360.0; - while (angle >= 360.0) - angle -= 360.0; - return angle; + while (angle < 0.0) + angle += 360.0; + while (angle >= 360.0) + angle -= 360.0; + return angle; } long NormalizeAngle(long angle) { - while (angle < 0) - angle += 3600; - while (angle >= 3600) - angle -= 3600; - return angle; + while (angle < 0) + angle += 3600; + while (angle >= 3600) + angle -= 3600; + return angle; } static long GetPadNumber(const wxString& field, int* width, int* height) @@ -327,282 +327,282 @@ static long GetPadNumber(const wxString& field, int* width, int* height) if (field.Length() == 0) return PIN_ANOMYM; - wxASSERT(width != NULL && height != NULL); - long pinnr = 0; - /* most footprints have numeric pin numbers, but BGA and PGA use a letter - followed by digits; in this case, the matrix size must be determined - as well */ - if (isalpha(field[0]) && isdigit(field[1])) { - long row = toupper(field[0]) - 'A' + 1; - if (row > 9) - row--; /* because 'I' is not used for grid arrays */ - if (row > 14) - row--; /* because 'O' is not used for grid arrays */ - if (row > 15) - row--; /* because 'Q' is not used for grid arrays */ - if (row > 16) - row--; /* because 'S' is not used for grid arrays */ - if (row > 20) - row--; /* because 'X' is not used for grid arrays */ - if (row > 21) - row--; /* because 'Z' is not used for grid arrays */ - wxString sub = field.Mid(1); - long col; - sub.ToLong(&col); - if (col > *width) - *width = col; - if (row > *height) - *height = row; - pinnr = *height * (row - 1) + col; - } else { - field.ToLong(&pinnr); - } - return pinnr; + wxASSERT(width != NULL && height != NULL); + long pinnr = 0; + /* most footprints have numeric pin numbers, but BGA and PGA use a letter + followed by digits; in this case, the matrix size must be determined + as well */ + if (isalpha(field[0]) && isdigit(field[1])) { + long row = toupper(field[0]) - 'A' + 1; + if (row > 9) + row--; /* because 'I' is not used for grid arrays */ + if (row > 14) + row--; /* because 'O' is not used for grid arrays */ + if (row > 15) + row--; /* because 'Q' is not used for grid arrays */ + if (row > 16) + row--; /* because 'S' is not used for grid arrays */ + if (row > 20) + row--; /* because 'X' is not used for grid arrays */ + if (row > 21) + row--; /* because 'Z' is not used for grid arrays */ + wxString sub = field.Mid(1); + long col; + sub.ToLong(&col); + if (col > *width) + *width = col; + if (row > *height) + *height = row; + pinnr = *height * (row - 1) + col; + } else { + field.ToLong(&pinnr); + } + return pinnr; } /** TranslateUnits() translates units between mm and 1/10th mil, but only - * for the legacy module format. + * for the legacy module format. */ bool TranslateUnits(wxArrayString& module, bool from_mm, bool to_mm) { - if ((from_mm && to_mm) || (!from_mm && !to_mm)) - return false; /* fom_mm and to_mm are both true or both false -> nothing to do */ - - bool inpad = false; - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - wxString keyword = GetToken(&line); - if (keyword.length() == 2 && keyword[0] == wxT('T') && isdigit(keyword[1])) { - double xpos = GetTokenDim(&line, from_mm); - double ypos = GetTokenDim(&line, from_mm); - double xsize = GetTokenDim(&line, from_mm); - double ysize = GetTokenDim(&line, from_mm); - long rot = GetTokenLong(&line); - double penwidth = GetTokenDim(&line, from_mm); - wxString mflag = GetToken(&line); - wxString visflag = GetToken(&line); - long layer = GetTokenLong(&line); - /* the "italic" flag may be absent and it may be "glued" to the text field */ - wxString iflag, text; - if (line[0] == '"' || (line.length() > 1 && line[1] == '"')) { - /* the italic flag is absent or it is glued to the text (no space between the fields) */ - if (line[0] != '"') { - iflag = iflag.Left(1); - line = line.Mid(1); - } else { - iflag = wxT("N"); /* assume "not italic", when absent */ - } - wxASSERT(line[0] == '"'); - text = GetToken(&line); /* this strips off the double quotes */ - } else { - iflag = GetToken(&line); - text = GetToken(&line); - } - if (to_mm) - module[idx] = wxString::Format(wxT("%s %.4f %.4f %.4f %.4f %ld %.4f %s %s %ld %s \"%s\""), - keyword.c_str(), MM(xpos), MM(ypos), MM(xsize), MM(ysize), - rot, MM(penwidth), mflag.c_str(), visflag.c_str(), - layer, iflag.c_str(), text.c_str()); - else - module[idx] = wxString::Format(wxT("%s %ld %ld %ld %ld %ld %ld %s %s %ld %s \"%s\""), - keyword.c_str(), MIL10(xpos), MIL10(ypos), MIL10(xsize), MIL10(ysize), - rot, MIL10(penwidth), mflag.c_str(), visflag.c_str(), - layer, iflag.c_str(), text.c_str()); - } else if (keyword.CmpNoCase(wxT("DS")) == 0 || keyword.CmpNoCase(wxT("DC")) == 0) { - double x1 = GetTokenDim(&line, from_mm); - double y1 = GetTokenDim(&line, from_mm); - double x2 = GetTokenDim(&line, from_mm); - double y2 = GetTokenDim(&line, from_mm); - double penwidth = GetTokenDim(&line, from_mm); - if (to_mm) - module[idx] = wxString::Format(wxT("%s %.4f %.4f %.4f %.4f %.4f %s"), - keyword.c_str(), MM(x1), MM(y1), MM(x2), MM(y2), - MM(penwidth), line.c_str()); - else - module[idx] = wxString::Format(wxT("%s %ld %ld %ld %ld %ld %s"), - keyword.c_str(), MIL10(x1), MIL10(y1), MIL10(x2), MIL10(y2), - MIL10(penwidth), line.c_str()); - } else if (keyword.CmpNoCase(wxT("DA")) == 0) { - double x1 = GetTokenDim(&line, from_mm); - double y1 = GetTokenDim(&line, from_mm); - double x2 = GetTokenDim(&line, from_mm); - double y2 = GetTokenDim(&line, from_mm); - long angle = GetTokenLong(&line); - double penwidth = GetTokenDim(&line, from_mm); - if (to_mm) - module[idx] = wxString::Format(wxT("%s %.4f %.4f %.4f %.4f %ld %.4f %s"), - keyword.c_str(), MM(x1), MM(y1), MM(x2), MM(y2), - angle, MM(penwidth), line.c_str()); - else - module[idx] = wxString::Format(wxT("%s %ld %ld %ld %ld %ld %ld %s"), - keyword.c_str(), MIL10(x1), MIL10(y1), MIL10(x2), MIL10(y2), - angle, MIL10(penwidth), line.c_str()); - } else if (keyword.CmpNoCase(wxT("DP")) == 0) { - long rsv1 = GetTokenLong(&line); - long rsv2 = GetTokenLong(&line); - long rsv3 = GetTokenLong(&line); - long rsv4 = GetTokenLong(&line); - long count = GetTokenLong(&line); - double penwidth = GetTokenDim(&line, from_mm); - if (to_mm) - module[idx] = wxString::Format(wxT("%s %ld %ld %ld %ld %ld %.4f %s"), - keyword.c_str(), rsv1, rsv2, rsv3, rsv4, - count, MM(penwidth), line.c_str()); - else - module[idx] = wxString::Format(wxT("%s %ld %ld %ld %ld %ld %ld %s"), - keyword.c_str(), rsv1, rsv2, rsv3, rsv4, - count, MIL10(penwidth), line.c_str()); - } else if (keyword.CmpNoCase(wxT("Dl")) == 0) { - double xpos = GetTokenDim(&line, from_mm); - double ypos = GetTokenDim(&line, from_mm); - if (to_mm) - module[idx] = wxString::Format(wxT("%s %.4f %.4f"), keyword.c_str(), MM(xpos), MM(ypos)); - else - module[idx] = wxString::Format(wxT("%s %ld %ld"), keyword.c_str(), MIL10(xpos), MIL10(ypos)); - } else if (keyword.CmpNoCase(wxT("$PAD")) == 0) { - inpad = true; - } else if (keyword.CmpNoCase(wxT("$EndPAD")) == 0) { - inpad = false; - } else if (keyword.CmpNoCase(wxT("Po")) == 0) { - if (inpad) { - double xpos = GetTokenDim(&line, from_mm); - double ypos = GetTokenDim(&line, from_mm); - if (to_mm) - module[idx] = wxString::Format(wxT("%s %.4f %.4f"), keyword.c_str(), MM(xpos), MM(ypos)); - else - module[idx] = wxString::Format(wxT("%s %ld %ld"), keyword.c_str(), MIL10(xpos), MIL10(ypos)); - } else { - /* the "Po" token must also be translated at the module level, as it - may have a non-zero position or angle; we do not care about the - position, but the angle must be preserved */ - GetToken(&line); - GetToken(&line); - long angle = GetTokenLong(&line); - module[idx] = wxString::Format(wxT("%s 0 0 %ld %s"), keyword.c_str(), angle, line.c_str()); - } - } else if (keyword.CmpNoCase(wxT("Sh")) == 0 && inpad) { - wxString name = GetToken(&line); - wxString type = GetToken(&line); - double width = GetTokenDim(&line, from_mm); - double height = GetTokenDim(&line, from_mm); - double xdelta = GetTokenDim(&line, from_mm); - double ydelta = GetTokenDim(&line, from_mm); - long rot = GetTokenLong(&line); - if (to_mm) - module[idx] = wxString::Format(wxT("%s \"%s\" %s %.4f %.4f %.4f %.4f %ld"), - keyword.c_str(), name.c_str(), type.c_str(), - MM(width), MM(height), MM(xdelta), MM(ydelta), rot); - else - module[idx] = wxString::Format(wxT("%s \"%s\" %s %ld %ld %ld %ld %ld"), - keyword.c_str(), name.c_str(), type.c_str(), - MIL10(width), MIL10(height), MIL10(xdelta), MIL10(ydelta), rot); - } else if (keyword.CmpNoCase(wxT("Dr")) == 0 && inpad) { - double size = GetTokenDim(&line, from_mm); - double xpos = GetTokenDim(&line, from_mm); - double ypos = GetTokenDim(&line, from_mm); - if (line.length() > 0) { - /* slotted hole */ - wxString type = GetToken(&line); - double xend = GetTokenDim(&line, from_mm); - double yend = GetTokenDim(&line, from_mm); - if (to_mm) - module[idx] = wxString::Format(wxT("%s %.4f %.4f %.4f %s %.4f %.4f"), - keyword.c_str(), MM(size), MM(xpos), MM(ypos), - type.c_str(), MM(xend), MM(yend)); - else - module[idx] = wxString::Format(wxT("%s %ld %ld %ld %s %ld %ld"), - keyword.c_str(), MIL10(size), MIL10(xpos), MIL10(ypos), - type.c_str(), MIL10(xend), MIL10(yend)); - } else { - if (to_mm) - module[idx] = wxString::Format(wxT("%s %.4f %.4f %.4f"), - keyword.c_str(), MM(size), MM(xpos), MM(ypos)); - else - module[idx] = wxString::Format(wxT("%s %ld %ld %ld"), - keyword.c_str(), MIL10(size), MIL10(xpos), MIL10(ypos)); - } - } else if (keyword.CmpNoCase(wxT("Le")) == 0 && inpad) { - /* length die */ - double size = GetTokenDim(&line, from_mm); - if (to_mm) - module[idx] = wxString::Format(wxT("%s %.4f"), keyword.c_str(), MM(size)); - else - module[idx] = wxString::Format(wxT("%s %ld"), keyword.c_str(), MIL10(size)); - } else if (keyword.CmpNoCase(wxT(".SolderPaste")) == 0 - || keyword.CmpNoCase(wxT(".SolderMask")) == 0 - || keyword.CmpNoCase(wxT(".LocalClearance")) == 0 - || keyword.CmpNoCase(wxT(".ThermalWidth")) == 0 - || keyword.CmpNoCase(wxT(".ThermalGap")) == 0) - { - wxASSERT(inpad); - double size = GetTokenDim(&line, from_mm); - if (to_mm) - module[idx] = wxString::Format(wxT("%s %.4f"), keyword.c_str(), MM(size)); - else - module[idx] = wxString::Format(wxT("%s %ld"), keyword.c_str(), MIL10(size)); - } - } - return true; + if ((from_mm && to_mm) || (!from_mm && !to_mm)) + return false; /* fom_mm and to_mm are both true or both false -> nothing to do */ + + bool inpad = false; + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + wxString keyword = GetToken(&line); + if (keyword.length() == 2 && keyword[0] == wxT('T') && isdigit(keyword[1])) { + double xpos = GetTokenDim(&line, from_mm); + double ypos = GetTokenDim(&line, from_mm); + double xsize = GetTokenDim(&line, from_mm); + double ysize = GetTokenDim(&line, from_mm); + long rot = GetTokenLong(&line); + double penwidth = GetTokenDim(&line, from_mm); + wxString mflag = GetToken(&line); + wxString visflag = GetToken(&line); + long layer = GetTokenLong(&line); + /* the "italic" flag may be absent and it may be "glued" to the text field */ + wxString iflag, text; + if (line[0] == '"' || (line.length() > 1 && line[1] == '"')) { + /* the italic flag is absent or it is glued to the text (no space between the fields) */ + if (line[0] != '"') { + iflag = iflag.Left(1); + line = line.Mid(1); + } else { + iflag = wxT("N"); /* assume "not italic", when absent */ + } + wxASSERT(line[0] == '"'); + text = GetToken(&line); /* this strips off the double quotes */ + } else { + iflag = GetToken(&line); + text = GetToken(&line); + } + if (to_mm) + module[idx] = wxString::Format(wxT("%s %.4f %.4f %.4f %.4f %ld %.4f %s %s %ld %s \"%s\""), + keyword.c_str(), MM(xpos), MM(ypos), MM(xsize), MM(ysize), + rot, MM(penwidth), mflag.c_str(), visflag.c_str(), + layer, iflag.c_str(), text.c_str()); + else + module[idx] = wxString::Format(wxT("%s %ld %ld %ld %ld %ld %ld %s %s %ld %s \"%s\""), + keyword.c_str(), MIL10(xpos), MIL10(ypos), MIL10(xsize), MIL10(ysize), + rot, MIL10(penwidth), mflag.c_str(), visflag.c_str(), + layer, iflag.c_str(), text.c_str()); + } else if (keyword.CmpNoCase(wxT("DS")) == 0 || keyword.CmpNoCase(wxT("DC")) == 0) { + double x1 = GetTokenDim(&line, from_mm); + double y1 = GetTokenDim(&line, from_mm); + double x2 = GetTokenDim(&line, from_mm); + double y2 = GetTokenDim(&line, from_mm); + double penwidth = GetTokenDim(&line, from_mm); + if (to_mm) + module[idx] = wxString::Format(wxT("%s %.4f %.4f %.4f %.4f %.4f %s"), + keyword.c_str(), MM(x1), MM(y1), MM(x2), MM(y2), + MM(penwidth), line.c_str()); + else + module[idx] = wxString::Format(wxT("%s %ld %ld %ld %ld %ld %s"), + keyword.c_str(), MIL10(x1), MIL10(y1), MIL10(x2), MIL10(y2), + MIL10(penwidth), line.c_str()); + } else if (keyword.CmpNoCase(wxT("DA")) == 0) { + double x1 = GetTokenDim(&line, from_mm); + double y1 = GetTokenDim(&line, from_mm); + double x2 = GetTokenDim(&line, from_mm); + double y2 = GetTokenDim(&line, from_mm); + long angle = GetTokenLong(&line); + double penwidth = GetTokenDim(&line, from_mm); + if (to_mm) + module[idx] = wxString::Format(wxT("%s %.4f %.4f %.4f %.4f %ld %.4f %s"), + keyword.c_str(), MM(x1), MM(y1), MM(x2), MM(y2), + angle, MM(penwidth), line.c_str()); + else + module[idx] = wxString::Format(wxT("%s %ld %ld %ld %ld %ld %ld %s"), + keyword.c_str(), MIL10(x1), MIL10(y1), MIL10(x2), MIL10(y2), + angle, MIL10(penwidth), line.c_str()); + } else if (keyword.CmpNoCase(wxT("DP")) == 0) { + long rsv1 = GetTokenLong(&line); + long rsv2 = GetTokenLong(&line); + long rsv3 = GetTokenLong(&line); + long rsv4 = GetTokenLong(&line); + long count = GetTokenLong(&line); + double penwidth = GetTokenDim(&line, from_mm); + if (to_mm) + module[idx] = wxString::Format(wxT("%s %ld %ld %ld %ld %ld %.4f %s"), + keyword.c_str(), rsv1, rsv2, rsv3, rsv4, + count, MM(penwidth), line.c_str()); + else + module[idx] = wxString::Format(wxT("%s %ld %ld %ld %ld %ld %ld %s"), + keyword.c_str(), rsv1, rsv2, rsv3, rsv4, + count, MIL10(penwidth), line.c_str()); + } else if (keyword.CmpNoCase(wxT("Dl")) == 0) { + double xpos = GetTokenDim(&line, from_mm); + double ypos = GetTokenDim(&line, from_mm); + if (to_mm) + module[idx] = wxString::Format(wxT("%s %.4f %.4f"), keyword.c_str(), MM(xpos), MM(ypos)); + else + module[idx] = wxString::Format(wxT("%s %ld %ld"), keyword.c_str(), MIL10(xpos), MIL10(ypos)); + } else if (keyword.CmpNoCase(wxT("$PAD")) == 0) { + inpad = true; + } else if (keyword.CmpNoCase(wxT("$EndPAD")) == 0) { + inpad = false; + } else if (keyword.CmpNoCase(wxT("Po")) == 0) { + if (inpad) { + double xpos = GetTokenDim(&line, from_mm); + double ypos = GetTokenDim(&line, from_mm); + if (to_mm) + module[idx] = wxString::Format(wxT("%s %.4f %.4f"), keyword.c_str(), MM(xpos), MM(ypos)); + else + module[idx] = wxString::Format(wxT("%s %ld %ld"), keyword.c_str(), MIL10(xpos), MIL10(ypos)); + } else { + /* the "Po" token must also be translated at the module level, as it + may have a non-zero position or angle; we do not care about the + position, but the angle must be preserved */ + GetToken(&line); + GetToken(&line); + long angle = GetTokenLong(&line); + module[idx] = wxString::Format(wxT("%s 0 0 %ld %s"), keyword.c_str(), angle, line.c_str()); + } + } else if (keyword.CmpNoCase(wxT("Sh")) == 0 && inpad) { + wxString name = GetToken(&line); + wxString type = GetToken(&line); + double width = GetTokenDim(&line, from_mm); + double height = GetTokenDim(&line, from_mm); + double xdelta = GetTokenDim(&line, from_mm); + double ydelta = GetTokenDim(&line, from_mm); + long rot = GetTokenLong(&line); + if (to_mm) + module[idx] = wxString::Format(wxT("%s \"%s\" %s %.4f %.4f %.4f %.4f %ld"), + keyword.c_str(), name.c_str(), type.c_str(), + MM(width), MM(height), MM(xdelta), MM(ydelta), rot); + else + module[idx] = wxString::Format(wxT("%s \"%s\" %s %ld %ld %ld %ld %ld"), + keyword.c_str(), name.c_str(), type.c_str(), + MIL10(width), MIL10(height), MIL10(xdelta), MIL10(ydelta), rot); + } else if (keyword.CmpNoCase(wxT("Dr")) == 0 && inpad) { + double size = GetTokenDim(&line, from_mm); + double xpos = GetTokenDim(&line, from_mm); + double ypos = GetTokenDim(&line, from_mm); + if (line.length() > 0) { + /* slotted hole */ + wxString type = GetToken(&line); + double xend = GetTokenDim(&line, from_mm); + double yend = GetTokenDim(&line, from_mm); + if (to_mm) + module[idx] = wxString::Format(wxT("%s %.4f %.4f %.4f %s %.4f %.4f"), + keyword.c_str(), MM(size), MM(xpos), MM(ypos), + type.c_str(), MM(xend), MM(yend)); + else + module[idx] = wxString::Format(wxT("%s %ld %ld %ld %s %ld %ld"), + keyword.c_str(), MIL10(size), MIL10(xpos), MIL10(ypos), + type.c_str(), MIL10(xend), MIL10(yend)); + } else { + if (to_mm) + module[idx] = wxString::Format(wxT("%s %.4f %.4f %.4f"), + keyword.c_str(), MM(size), MM(xpos), MM(ypos)); + else + module[idx] = wxString::Format(wxT("%s %ld %ld %ld"), + keyword.c_str(), MIL10(size), MIL10(xpos), MIL10(ypos)); + } + } else if (keyword.CmpNoCase(wxT("Le")) == 0 && inpad) { + /* length die */ + double size = GetTokenDim(&line, from_mm); + if (to_mm) + module[idx] = wxString::Format(wxT("%s %.4f"), keyword.c_str(), MM(size)); + else + module[idx] = wxString::Format(wxT("%s %ld"), keyword.c_str(), MIL10(size)); + } else if (keyword.CmpNoCase(wxT(".SolderPaste")) == 0 + || keyword.CmpNoCase(wxT(".SolderMask")) == 0 + || keyword.CmpNoCase(wxT(".LocalClearance")) == 0 + || keyword.CmpNoCase(wxT(".ThermalWidth")) == 0 + || keyword.CmpNoCase(wxT(".ThermalGap")) == 0) + { + wxASSERT(inpad); + double size = GetTokenDim(&line, from_mm); + if (to_mm) + module[idx] = wxString::Format(wxT("%s %.4f"), keyword.c_str(), MM(size)); + else + module[idx] = wxString::Format(wxT("%s %ld"), keyword.c_str(), MIL10(size)); + } + } + return true; } static struct { - long number; - const wxChar* name; + long number; + const wxChar* name; } LayerMap[] = { - { 0, wxT("B.Cu") }, - { 1, wxT("Inner1.Cu") }, - { 2, wxT("Inner2.Cu") }, - { 3, wxT("Inner3.Cu") }, - { 4, wxT("Inner4.Cu") }, - { 5, wxT("Inner5.Cu") }, - { 6, wxT("Inner6.Cu") }, - { 7, wxT("Inner7.Cu") }, - { 8, wxT("Inner8.Cu") }, - { 9, wxT("Inner9.Cu") }, - { 10, wxT("Inner10.Cu") }, - { 11, wxT("Inner11.Cu") }, - { 12, wxT("Inner12.Cu") }, - { 13, wxT("Inner13.Cu") }, - { 14, wxT("Inner14.Cu") }, - { 15, wxT("F.Cu") }, - { 16, wxT("B.Adhes") }, - { 17, wxT("F.Adhes") }, - { 18, wxT("B.Paste") }, - { 19, wxT("F.Paste") }, - { 20, wxT("B.SilkS") }, - { 21, wxT("F.SilkS") }, - { 22, wxT("B.Mask") }, - { 23, wxT("F.Mask") }, - { 24, wxT("Dwgs.User") }, - { 25, wxT("Cmts.User") }, - { 26, wxT("Eco1.User") }, - { 27, wxT("Eco2.User") }, - { 28, wxT("Edge.Cuts") }, - { 29, wxT("Margin") }, - { 30, wxT("F.CrtYd") }, - { 31, wxT("B.CrtYd") }, - { 32, wxT("F.Fab") }, - { 33, wxT("B.Fab") }, + { 0, wxT("B.Cu") }, + { 1, wxT("Inner1.Cu") }, + { 2, wxT("Inner2.Cu") }, + { 3, wxT("Inner3.Cu") }, + { 4, wxT("Inner4.Cu") }, + { 5, wxT("Inner5.Cu") }, + { 6, wxT("Inner6.Cu") }, + { 7, wxT("Inner7.Cu") }, + { 8, wxT("Inner8.Cu") }, + { 9, wxT("Inner9.Cu") }, + { 10, wxT("Inner10.Cu") }, + { 11, wxT("Inner11.Cu") }, + { 12, wxT("Inner12.Cu") }, + { 13, wxT("Inner13.Cu") }, + { 14, wxT("Inner14.Cu") }, + { 15, wxT("F.Cu") }, + { 16, wxT("B.Adhes") }, + { 17, wxT("F.Adhes") }, + { 18, wxT("B.Paste") }, + { 19, wxT("F.Paste") }, + { 20, wxT("B.SilkS") }, + { 21, wxT("F.SilkS") }, + { 22, wxT("B.Mask") }, + { 23, wxT("F.Mask") }, + { 24, wxT("Dwgs.User") }, + { 25, wxT("Cmts.User") }, + { 26, wxT("Eco1.User") }, + { 27, wxT("Eco2.User") }, + { 28, wxT("Edge.Cuts") }, + { 29, wxT("Margin") }, + { 30, wxT("F.CrtYd") }, + { 31, wxT("B.CrtYd") }, + { 32, wxT("F.Fab") }, + { 33, wxT("B.Fab") }, }; static const wxChar* LayerName(int index) { - for (unsigned i = 0; i < sizearray(LayerMap); i++) { - if (LayerMap[i].number == index) - return LayerMap[i].name; - } - wxASSERT(false); - return wxT("unknown"); + for (unsigned i = 0; i < sizearray(LayerMap); i++) { + if (LayerMap[i].number == index) + return LayerMap[i].name; + } + wxASSERT(false); + return wxT("unknown"); } static long LayerNumber(const wxString& name) { - for (unsigned i = 0; i < sizearray(LayerMap); i++) { - if (name.CmpNoCase(LayerMap[i].name) == 0) - return LayerMap[i].number; - } - wxASSERT(false); - return -1; + for (unsigned i = 0; i < sizearray(LayerMap); i++) { + if (name.CmpNoCase(LayerMap[i].name) == 0) + return LayerMap[i].number; + } + wxASSERT(false); + return -1; } /** TranslateToSexpr() translates a legacy module to s-expression. The legacy @@ -610,1036 +610,1036 @@ static long LayerNumber(const wxString& name) */ void TranslateToSexpr(wxArrayString* output, const wxArrayString& module) { - wxASSERT(output != 0); - output->Clear(); - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - wxString keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("$MODULE")) == 0) { - wxString name = GetToken(&line); - /* find extra information to add to this header line */ - int layer = -1, locked = -1, placed = -1; - unsigned long timestamp = 0; - for (unsigned i = idx + 1; i < module.Count(); i++) { - line = module[i]; - keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("Po")) == 0) { - GetToken(&line); /* ignore xpos */ - GetToken(&line); /* ignore ypos */ - GetToken(&line); /* ignore rotation */ - layer = GetTokenLong(&line); - wxString field = GetToken(&line); - field.ToULong(×tamp, 16); - GetToken(&line); /* ignore timestamp 2 */ - locked = (line[0] == wxT('F')); - placed = (line[1] == wxT('P')); - } else if (keyword[0] == wxT('$')) { - break; - } - } - wxString newline; - newline = wxString::Format(wxT("(module \"%s\""), name.c_str()); - if (layer >= 0) - newline += wxString::Format(wxT(" (layer %s)"), LayerName(layer)); - if (locked > 0) - newline += wxT(" locked"); - if (placed > 0) - newline += wxT(" placed"); - output->Add(newline); - if (timestamp > 0) { - newline = wxString::Format(wxT("(tedit %X)"), timestamp); - output->Add(newline); - } - } else if (keyword.CmpNoCase(wxT("$EndMODULE")) == 0) { - output->Add(wxT(")")); - } else if (keyword.CmpNoCase(wxT("AR")) == 0 && line.length() > 0) { - output->Insert(wxT("#template ") + line, 0); - } else if (keyword.CmpNoCase(wxT("Po")) == 0) { - double xpos = GetTokenDim(&line, true); - double ypos = GetTokenDim(&line, true); - long angle = GetTokenLong(&line); - /* the "module position" is redundant for library modules, so we only copy - it to the output when it is non-zero */ - if (!Equal(xpos, 0.0) || !Equal(ypos, 0.0) || angle != 0) { - wxString newline; - if (angle == 0) - newline = wxString::Format(wxT("(at %.4f %.4f)"), xpos, ypos); - else - newline = wxString::Format(wxT("(at %.4f %.4f %ld)"), xpos, ypos, angle); - output->Add(newline); - } - } else if (keyword.CmpNoCase(wxT("At")) == 0) { - wxString type = GetToken(&line); - if (type.CmpNoCase(wxT("SMD")) == 0) - output->Add(wxT("(attr smd)")); - } else if (toupper(keyword[0]) == 'T' && isdigit(keyword[1])) { - int type = keyword[1] - '0'; - double xpos = GetTokenDim(&line, true); - double ypos = GetTokenDim(&line, true); - double textwidth = GetTokenDim(&line, true); - double textheight = GetTokenDim(&line, true); - long angle = GetTokenLong(&line); - double penwidth = GetTokenDim(&line, true); - GetToken(&line); /* ignore mirror */ - wxString visible = GetToken(&line); - long layer = GetTokenLong(&line); - GetToken(&line); /* ignore italic */ - wxString text = GetToken(&line); - wxString newline = wxT("(fp_text "); - switch (type) { - case 0: - newline += wxT("reference"); - break; - case 1: - newline += wxT("value"); - break; - default: - newline += wxT("user"); - } - newline += wxT(" \"") + text + wxT("\""); - if (angle == 0) - newline += wxString::Format(wxT(" (at %.4f %.4f)"), xpos, ypos); - else - newline += wxString::Format(wxT(" (at %.4f %.4f %.1f)"), xpos, ypos, angle / 10.0); - if (layer >= 0) - newline += wxString::Format(wxT(" (layer %s)"), LayerName(layer)); - if (visible == wxT('H') || visible == wxT('I')) - newline += wxT(" hide"); - newline += wxString::Format(wxT(" (effects (font (size %.4f %.4f) (thickness %.4f))))"), textwidth, textheight, penwidth); - output->Add(newline); - } else if (keyword.CmpNoCase(wxT("DS")) == 0) { - double x1 = GetTokenDim(&line, true); - double y1 = GetTokenDim(&line, true); - double x2 = GetTokenDim(&line, true); - double y2 = GetTokenDim(&line, true); - double penwidth = GetTokenDim(&line, true); - long layer = GetTokenLong(&line); - wxString newline = wxString::Format(wxT("(fp_line (start %.4f %.4f) (end %.4f %.4f) (layer %s) (width %.4f))"), - x1, y1, x2, y2, LayerName(layer), penwidth); - output->Add(newline); - } else if (keyword.CmpNoCase(wxT("DC")) == 0) { - double xpos = GetTokenDim(&line, true); - double ypos = GetTokenDim(&line, true); - double xpt = GetTokenDim(&line, true); - double ypt = GetTokenDim(&line, true); - double penwidth = GetTokenDim(&line, true); - long layer = GetTokenLong(&line); - wxString newline = wxString::Format(wxT("(fp_circle (center %.4f %.4f) (end %.4f %.4f) (layer %s) (width %.4f))"), - xpos, ypos, xpt, ypt, LayerName(layer), penwidth); - output->Add(newline); - } else if (keyword.CmpNoCase(wxT("DA")) == 0) { - double xpos = GetTokenDim(&line, true); - double ypos = GetTokenDim(&line, true); - double xpt = GetTokenDim(&line, true); - double ypt = GetTokenDim(&line, true); - long angle = GetTokenLong(&line); - double penwidth = GetTokenDim(&line, true); - long layer = GetTokenLong(&line); - wxString newline = wxString::Format(wxT("(fp_arc (start %.4f %.4f) (end %.4f %.4f) (angle %.1f) (layer %s) (width %.4f))"), - xpos, ypos, xpt, ypt, angle / 10.0, LayerName(layer), penwidth); - output->Add(newline); - } else if (keyword.CmpNoCase(wxT("DP")) == 0) { - GetToken(&line); - GetToken(&line); - GetToken(&line); - GetToken(&line); - long count = GetTokenLong(&line); - double penwidth = GetTokenDim(&line, true); - long layer = GetTokenLong(&line); - wxString newline = wxT("(fp_poly (pts"); - while (count-- > 0) { - idx++; - line = module[idx]; - wxString keyword = GetToken(&line); - wxASSERT(keyword.CmpNoCase(wxT("Dl")) == 0); - double x = GetTokenDim(&line, true); - double y = GetTokenDim(&line, true); - newline += wxString::Format(wxT(" (xy %.4f %.4f)"), x, y); - } - newline += wxT(")"); - newline += wxString::Format(wxT(" (layer %s) (width %.4f))"), LayerName(layer), penwidth); - output->Add(newline); - } else if (keyword.CmpNoCase(wxT("At")) == 0) { - wxString type = GetToken(&line); - if (type.CmpNoCase(wxT("SMD")) == 0) - output->Add(wxT("(attr smd)")); - } else if (keyword.CmpNoCase(wxT("Cd")) == 0) { - output->Add(wxT("(descr \"") + line + wxT("\")")); - } else if (keyword.CmpNoCase(wxT("Kw")) == 0) { - output->Add(wxT("(tags \"") + line + wxT("\")")); - } else if (keyword.CmpNoCase(wxT("Op")) == 0) { - long pen90 = GetTokenLong(&line); - long pen180 = GetTokenLong(&line); - wxString newline; - if (pen90 != 0) { - newline = wxString::Format(wxT("(autoplace_cost90 %ld)"), pen90); - output->Add(newline); - } - if (pen180 != 0) { - newline = wxString::Format(wxT("(autoplace_cost90 %ld)"), pen180); - output->Add(newline); - } - } else if (keyword.CmpNoCase(wxT(".SolderMask")) == 0) { - double dim = GetTokenDim(&line, true); - wxString newline = wxString::Format(wxT("(solder_mask_margin %.4f)"), dim); - output->Add(newline); - } else if (keyword.CmpNoCase(wxT(".SolderPaste")) == 0) { - double dim = GetTokenDim(&line, true); - wxString newline = wxString::Format(wxT("(solder_paste_margin %.4f)"), dim); - output->Add(newline); - } else if (keyword.CmpNoCase(wxT(".SolderPasteRatio")) == 0) { - long ratio = GetTokenLong(&line); - wxString newline = wxString::Format(wxT("(solder_paste_ratio %ld)"), ratio); - output->Add(newline); - } else if (keyword.CmpNoCase(wxT(".LocalClearance")) == 0) { - double dim = GetTokenDim(&line, true); - wxString newline = wxString::Format(wxT("(clearance %.4f)"), dim); - output->Add(newline); - } else if (keyword.CmpNoCase(wxT(".ZoneConnection")) == 0) { - long val = GetTokenLong(&line); - wxString newline = wxString::Format(wxT("(zone_connect %ld)"), val); - output->Add(newline); - } else if (keyword.CmpNoCase(wxT(".ThermalWidth")) == 0) { - double dim = GetTokenDim(&line, true); - wxString newline = wxString::Format(wxT("(thermal_width %.4f)"), dim); - output->Add(newline); - } else if (keyword.CmpNoCase(wxT(".ThermalGap")) == 0) { - double dim = GetTokenDim(&line, true); - wxString newline = wxString::Format(wxT("(thermal_gap %.4f)"), dim); - output->Add(newline); - } else if (keyword.CmpNoCase(wxT("$PAD")) == 0) { - wxString name, type, shape; - double px = 0, py = 0, pw = 0, ph = 0, tx = 0, ty = 0; - double drillx = 0, drilly = 0, drillwidth = 0, drillheight = 0; - double die_length = 0, solder_mask_margin = 0, clearance = 0; - double solder_paste_margin = 0, thermal_width = 0, thermal_gap = 0; - long solder_paste_ratio = -1, zone_connect = -1; - long angle = 0; - long layermask = 0; - while (idx < module.Count()) { - idx++; - line = module[idx]; - line.Trim(); - if (line.CmpNoCase(wxT("$EndPAD")) == 0) - break; - keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("Po")) == 0) { - px = GetTokenDim(&line, true); - py = GetTokenDim(&line, true); - } else if (keyword.CmpNoCase(wxT("Sh")) == 0) { - name = GetToken(&line); - shape = GetToken(&line); - pw = GetTokenDim(&line, true); - ph = GetTokenDim(&line, true); - tx = GetTokenDim(&line, true); - ty = GetTokenDim(&line, true); - angle = GetTokenLong(&line); - /* convert naming conventions */ - switch (toupper(shape[0])) { - case 'C': - shape = wxT("circle"); - break; - case 'R': - shape = wxT("rect"); - break; - case 'O': - shape = wxT("oval"); - break; - case 'T': - shape = wxT("trapezoid"); - break; - } - } else if (keyword.CmpNoCase(wxT("Dr")) == 0) { - drillwidth = GetTokenDim(&line, true); - drillx = GetTokenDim(&line, true); - drilly = GetTokenDim(&line, true); - if (line.length() > 0) { - GetToken(&line); /* ignore 'O' */ - drillwidth = GetTokenDim(&line, true); - drillheight = GetTokenDim(&line, true); - } else { - drillheight = drillwidth; - } - } else if (keyword.CmpNoCase(wxT("At")) == 0) { - type = GetToken(&line); - GetToken(&line); /* skip unknown attribute */ - wxString field = GetToken(&line); - field.ToLong(&layermask, 16); - /* convert naming conventions */ - if (type.CmpNoCase(wxT("STD")) == 0) - type = wxT("thru_hole"); - else if (type.CmpNoCase(wxT("SMD")) == 0) - type = wxT("smd"); - else if (type.CmpNoCase(wxT("CONN")) == 0) - type = wxT("connect"); - else if (type.CmpNoCase(wxT("HOLE")) == 0) - type = wxT("np_thru_hole"); - } else if (keyword.CmpNoCase(wxT("Le")) == 0) { - die_length = GetTokenDim(&line, true); - } else if (keyword.CmpNoCase(wxT(".SolderMask")) == 0) { - solder_mask_margin = GetTokenDim(&line, true); - } else if (keyword.CmpNoCase(wxT(".LocalClearance")) == 0) { - clearance = GetTokenDim(&line, true); - } else if (keyword.CmpNoCase(wxT(".SolderPaste")) == 0) { - solder_paste_margin = GetTokenDim(&line, true); - } else if (keyword.CmpNoCase(wxT(".SolderPasteRatio")) == 0) { - solder_paste_ratio = GetTokenLong(&line); - } else if (keyword.CmpNoCase(wxT(".ZoneConnection")) == 0) { - zone_connect = GetTokenLong(&line); - } else if (keyword.CmpNoCase(wxT(".ThermalWidth")) == 0) { - thermal_width = GetTokenDim(&line, true); - } else if (keyword.CmpNoCase(wxT(".ThermalGap")) == 0) { - thermal_gap = GetTokenDim(&line, true); - } - } - wxString newline = wxString::Format(wxT("(pad \"%s\" %s %s"), name.c_str(), type.c_str(), shape.c_str()); - if (angle != 0) - newline += wxString::Format(wxT(" (at %.4f %.4f %.1f)"), px, py, angle / 10.0); - else - newline += wxString::Format(wxT(" (at %.4f %.4f)"), px, py); - newline += wxString::Format(wxT(" (size %.4f %.4f)"), pw, ph); - if (!Equal(tx, 0.0) || !Equal(ty, 0.0)) - newline += wxString::Format(wxT(" (rect_delta %.4f %.4f)"), tx, ty); - if ((type.CmpNoCase(wxT("thru_hole")) == 0 || type.CmpNoCase(wxT("np_thru_hole")) == 0) && drillwidth > EPSILON) { - if (Equal(drillwidth, drillheight)) - newline += wxString::Format(wxT(" (drill %.4f (offset %.4f %.4f))"), drillwidth, drillx, drilly); - else - newline += wxString::Format(wxT(" (drill oval %.4f %.4f (offset %.4f %.4f))"), drillwidth, drillheight, drillx, drilly); - } - newline += wxT(" (layers"); - if ((layermask & 0x0000ffff) == 0x0000ffff) { - newline += wxT(" *.Cu"); - layermask &= ~ 0x0000ffff; - } - if ((layermask & 0x00300000) == 0x00300000) { - newline += wxT(" *.Silk"); - layermask &= ~ 0x00300000; - } - if ((layermask & 0x00c00000) == 0x00c00000) { - newline += wxT(" *.Mask"); - layermask &= ~ 0x00c00000; - } - for (long lidx = 0; lidx < 32; lidx++) { - if ((layermask & (1 << lidx)) != 0) { - newline += wxT(" "); - newline += LayerName(lidx); - } - } - newline += wxT(")"); - if (die_length > EPSILON) - newline += wxString::Format(wxT(" (die_length %.4f)"), die_length); - if (solder_mask_margin > EPSILON) - newline += wxString::Format(wxT(" (solder_mask_margin %.4f)"), solder_mask_margin); - if (clearance > EPSILON) - newline += wxString::Format(wxT(" (clearance %.4f)"), clearance); - if (solder_paste_margin > EPSILON) - newline += wxString::Format(wxT(" (solder_paste_margin %.4f)"), solder_paste_margin); - if (solder_paste_ratio >= 0) - newline += wxString::Format(wxT(" (solder_paste_ratio %ld)"), solder_paste_ratio); - if (zone_connect >= 0) - newline += wxString::Format(wxT(" (zone_connect %ld)"), zone_connect); - if (thermal_width > EPSILON) - newline += wxString::Format(wxT(" (thermal_width %.4f)"), thermal_width); - if (thermal_gap > EPSILON) - newline += wxString::Format(wxT(" (thermal_gap %.4f)"), thermal_gap); - newline += wxT(")"); - output->Add(newline); - } else if (keyword.CmpNoCase(wxT("$SHAPE3D")) == 0) { - wxString path = wxEmptyString; - double ox = 0, oy = 0, oz = 0; - double sx = 1, sy = 1, sz = 1; - double rx = 0, ry = 0, rz = 0; - while (idx < module.Count()) { - idx++; - line = module[idx]; - line.Trim(); - if (line.CmpNoCase(wxT("$EndSHAPE3D")) == 0) - break; - keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("Na")) == 0) { - path = line; - if (path[0] != wxT('"')) - path = wxT("\"") + path + wxT("\""); - } else if (keyword.CmpNoCase(wxT("Of")) == 0) { - ox = GetTokenDim(&line, true); - oy = GetTokenDim(&line, true); - oz = GetTokenDim(&line, true); - } else if (keyword.CmpNoCase(wxT("Sc")) == 0) { - sx = GetTokenDim(&line, true); - sy = GetTokenDim(&line, true); - sz = GetTokenDim(&line, true); - } else if (keyword.CmpNoCase(wxT("Ro")) == 0) { - rx = GetTokenDim(&line, true); - ry = GetTokenDim(&line, true); - rz = GetTokenDim(&line, true); - } - } - wxString newline = wxString::Format(wxT("(model %s (at (xyz %.4f %.4f %.4f)) (scale (xyz %.4f %.4f %.4f)) (rotate (xyz %.4f %.4f %.4f)))"), - path.c_str(), ox, oy, oz, sx, sy, sz, rx, ry, rz); - output->Add(newline); - } - } + wxASSERT(output != 0); + output->Clear(); + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + wxString keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("$MODULE")) == 0) { + wxString name = GetToken(&line); + /* find extra information to add to this header line */ + int layer = -1, locked = -1, placed = -1; + unsigned long timestamp = 0; + for (unsigned i = idx + 1; i < module.Count(); i++) { + line = module[i]; + keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("Po")) == 0) { + GetToken(&line); /* ignore xpos */ + GetToken(&line); /* ignore ypos */ + GetToken(&line); /* ignore rotation */ + layer = GetTokenLong(&line); + wxString field = GetToken(&line); + field.ToULong(×tamp, 16); + GetToken(&line); /* ignore timestamp 2 */ + locked = (line[0] == wxT('F')); + placed = (line[1] == wxT('P')); + } else if (keyword[0] == wxT('$')) { + break; + } + } + wxString newline; + newline = wxString::Format(wxT("(module \"%s\""), name.c_str()); + if (layer >= 0) + newline += wxString::Format(wxT(" (layer %s)"), LayerName(layer)); + if (locked > 0) + newline += wxT(" locked"); + if (placed > 0) + newline += wxT(" placed"); + output->Add(newline); + if (timestamp > 0) { + newline = wxString::Format(wxT("(tedit %X)"), timestamp); + output->Add(newline); + } + } else if (keyword.CmpNoCase(wxT("$EndMODULE")) == 0) { + output->Add(wxT(")")); + } else if (keyword.CmpNoCase(wxT("AR")) == 0 && line.length() > 0) { + output->Insert(wxT("#template ") + line, 0); + } else if (keyword.CmpNoCase(wxT("Po")) == 0) { + double xpos = GetTokenDim(&line, true); + double ypos = GetTokenDim(&line, true); + long angle = GetTokenLong(&line); + /* the "module position" is redundant for library modules, so we only copy + it to the output when it is non-zero */ + if (!Equal(xpos, 0.0) || !Equal(ypos, 0.0) || angle != 0) { + wxString newline; + if (angle == 0) + newline = wxString::Format(wxT("(at %.4f %.4f)"), xpos, ypos); + else + newline = wxString::Format(wxT("(at %.4f %.4f %ld)"), xpos, ypos, angle); + output->Add(newline); + } + } else if (keyword.CmpNoCase(wxT("At")) == 0) { + wxString type = GetToken(&line); + if (type.CmpNoCase(wxT("SMD")) == 0) + output->Add(wxT("(attr smd)")); + } else if (toupper(keyword[0]) == 'T' && isdigit(keyword[1])) { + int type = keyword[1] - '0'; + double xpos = GetTokenDim(&line, true); + double ypos = GetTokenDim(&line, true); + double textwidth = GetTokenDim(&line, true); + double textheight = GetTokenDim(&line, true); + long angle = GetTokenLong(&line); + double penwidth = GetTokenDim(&line, true); + GetToken(&line); /* ignore mirror */ + wxString visible = GetToken(&line); + long layer = GetTokenLong(&line); + GetToken(&line); /* ignore italic */ + wxString text = GetToken(&line); + wxString newline = wxT("(fp_text "); + switch (type) { + case 0: + newline += wxT("reference"); + break; + case 1: + newline += wxT("value"); + break; + default: + newline += wxT("user"); + } + newline += wxT(" \"") + text + wxT("\""); + if (angle == 0) + newline += wxString::Format(wxT(" (at %.4f %.4f)"), xpos, ypos); + else + newline += wxString::Format(wxT(" (at %.4f %.4f %.1f)"), xpos, ypos, angle / 10.0); + if (layer >= 0) + newline += wxString::Format(wxT(" (layer %s)"), LayerName(layer)); + if (visible == wxT('H') || visible == wxT('I')) + newline += wxT(" hide"); + newline += wxString::Format(wxT(" (effects (font (size %.4f %.4f) (thickness %.4f))))"), textwidth, textheight, penwidth); + output->Add(newline); + } else if (keyword.CmpNoCase(wxT("DS")) == 0) { + double x1 = GetTokenDim(&line, true); + double y1 = GetTokenDim(&line, true); + double x2 = GetTokenDim(&line, true); + double y2 = GetTokenDim(&line, true); + double penwidth = GetTokenDim(&line, true); + long layer = GetTokenLong(&line); + wxString newline = wxString::Format(wxT("(fp_line (start %.4f %.4f) (end %.4f %.4f) (layer %s) (width %.4f))"), + x1, y1, x2, y2, LayerName(layer), penwidth); + output->Add(newline); + } else if (keyword.CmpNoCase(wxT("DC")) == 0) { + double xpos = GetTokenDim(&line, true); + double ypos = GetTokenDim(&line, true); + double xpt = GetTokenDim(&line, true); + double ypt = GetTokenDim(&line, true); + double penwidth = GetTokenDim(&line, true); + long layer = GetTokenLong(&line); + wxString newline = wxString::Format(wxT("(fp_circle (center %.4f %.4f) (end %.4f %.4f) (layer %s) (width %.4f))"), + xpos, ypos, xpt, ypt, LayerName(layer), penwidth); + output->Add(newline); + } else if (keyword.CmpNoCase(wxT("DA")) == 0) { + double xpos = GetTokenDim(&line, true); + double ypos = GetTokenDim(&line, true); + double xpt = GetTokenDim(&line, true); + double ypt = GetTokenDim(&line, true); + long angle = GetTokenLong(&line); + double penwidth = GetTokenDim(&line, true); + long layer = GetTokenLong(&line); + wxString newline = wxString::Format(wxT("(fp_arc (start %.4f %.4f) (end %.4f %.4f) (angle %.1f) (layer %s) (width %.4f))"), + xpos, ypos, xpt, ypt, angle / 10.0, LayerName(layer), penwidth); + output->Add(newline); + } else if (keyword.CmpNoCase(wxT("DP")) == 0) { + GetToken(&line); + GetToken(&line); + GetToken(&line); + GetToken(&line); + long count = GetTokenLong(&line); + double penwidth = GetTokenDim(&line, true); + long layer = GetTokenLong(&line); + wxString newline = wxT("(fp_poly (pts"); + while (count-- > 0) { + idx++; + line = module[idx]; + wxString keyword = GetToken(&line); + wxASSERT(keyword.CmpNoCase(wxT("Dl")) == 0); + double x = GetTokenDim(&line, true); + double y = GetTokenDim(&line, true); + newline += wxString::Format(wxT(" (xy %.4f %.4f)"), x, y); + } + newline += wxT(")"); + newline += wxString::Format(wxT(" (layer %s) (width %.4f))"), LayerName(layer), penwidth); + output->Add(newline); + } else if (keyword.CmpNoCase(wxT("At")) == 0) { + wxString type = GetToken(&line); + if (type.CmpNoCase(wxT("SMD")) == 0) + output->Add(wxT("(attr smd)")); + } else if (keyword.CmpNoCase(wxT("Cd")) == 0) { + output->Add(wxT("(descr \"") + line + wxT("\")")); + } else if (keyword.CmpNoCase(wxT("Kw")) == 0) { + output->Add(wxT("(tags \"") + line + wxT("\")")); + } else if (keyword.CmpNoCase(wxT("Op")) == 0) { + long pen90 = GetTokenLong(&line); + long pen180 = GetTokenLong(&line); + wxString newline; + if (pen90 != 0) { + newline = wxString::Format(wxT("(autoplace_cost90 %ld)"), pen90); + output->Add(newline); + } + if (pen180 != 0) { + newline = wxString::Format(wxT("(autoplace_cost90 %ld)"), pen180); + output->Add(newline); + } + } else if (keyword.CmpNoCase(wxT(".SolderMask")) == 0) { + double dim = GetTokenDim(&line, true); + wxString newline = wxString::Format(wxT("(solder_mask_margin %.4f)"), dim); + output->Add(newline); + } else if (keyword.CmpNoCase(wxT(".SolderPaste")) == 0) { + double dim = GetTokenDim(&line, true); + wxString newline = wxString::Format(wxT("(solder_paste_margin %.4f)"), dim); + output->Add(newline); + } else if (keyword.CmpNoCase(wxT(".SolderPasteRatio")) == 0) { + long ratio = GetTokenLong(&line); + wxString newline = wxString::Format(wxT("(solder_paste_ratio %ld)"), ratio); + output->Add(newline); + } else if (keyword.CmpNoCase(wxT(".LocalClearance")) == 0) { + double dim = GetTokenDim(&line, true); + wxString newline = wxString::Format(wxT("(clearance %.4f)"), dim); + output->Add(newline); + } else if (keyword.CmpNoCase(wxT(".ZoneConnection")) == 0) { + long val = GetTokenLong(&line); + wxString newline = wxString::Format(wxT("(zone_connect %ld)"), val); + output->Add(newline); + } else if (keyword.CmpNoCase(wxT(".ThermalWidth")) == 0) { + double dim = GetTokenDim(&line, true); + wxString newline = wxString::Format(wxT("(thermal_width %.4f)"), dim); + output->Add(newline); + } else if (keyword.CmpNoCase(wxT(".ThermalGap")) == 0) { + double dim = GetTokenDim(&line, true); + wxString newline = wxString::Format(wxT("(thermal_gap %.4f)"), dim); + output->Add(newline); + } else if (keyword.CmpNoCase(wxT("$PAD")) == 0) { + wxString name, type, shape; + double px = 0, py = 0, pw = 0, ph = 0, tx = 0, ty = 0; + double drillx = 0, drilly = 0, drillwidth = 0, drillheight = 0; + double die_length = 0, solder_mask_margin = 0, clearance = 0; + double solder_paste_margin = 0, thermal_width = 0, thermal_gap = 0; + long solder_paste_ratio = -1, zone_connect = -1; + long angle = 0; + long layermask = 0; + while (idx < module.Count()) { + idx++; + line = module[idx]; + line.Trim(); + if (line.CmpNoCase(wxT("$EndPAD")) == 0) + break; + keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("Po")) == 0) { + px = GetTokenDim(&line, true); + py = GetTokenDim(&line, true); + } else if (keyword.CmpNoCase(wxT("Sh")) == 0) { + name = GetToken(&line); + shape = GetToken(&line); + pw = GetTokenDim(&line, true); + ph = GetTokenDim(&line, true); + tx = GetTokenDim(&line, true); + ty = GetTokenDim(&line, true); + angle = GetTokenLong(&line); + /* convert naming conventions */ + switch (toupper(shape[0])) { + case 'C': + shape = wxT("circle"); + break; + case 'R': + shape = wxT("rect"); + break; + case 'O': + shape = wxT("oval"); + break; + case 'T': + shape = wxT("trapezoid"); + break; + } + } else if (keyword.CmpNoCase(wxT("Dr")) == 0) { + drillwidth = GetTokenDim(&line, true); + drillx = GetTokenDim(&line, true); + drilly = GetTokenDim(&line, true); + if (line.length() > 0) { + GetToken(&line); /* ignore 'O' */ + drillwidth = GetTokenDim(&line, true); + drillheight = GetTokenDim(&line, true); + } else { + drillheight = drillwidth; + } + } else if (keyword.CmpNoCase(wxT("At")) == 0) { + type = GetToken(&line); + GetToken(&line); /* skip unknown attribute */ + wxString field = GetToken(&line); + field.ToLong(&layermask, 16); + /* convert naming conventions */ + if (type.CmpNoCase(wxT("STD")) == 0) + type = wxT("thru_hole"); + else if (type.CmpNoCase(wxT("SMD")) == 0) + type = wxT("smd"); + else if (type.CmpNoCase(wxT("CONN")) == 0) + type = wxT("connect"); + else if (type.CmpNoCase(wxT("HOLE")) == 0) + type = wxT("np_thru_hole"); + } else if (keyword.CmpNoCase(wxT("Le")) == 0) { + die_length = GetTokenDim(&line, true); + } else if (keyword.CmpNoCase(wxT(".SolderMask")) == 0) { + solder_mask_margin = GetTokenDim(&line, true); + } else if (keyword.CmpNoCase(wxT(".LocalClearance")) == 0) { + clearance = GetTokenDim(&line, true); + } else if (keyword.CmpNoCase(wxT(".SolderPaste")) == 0) { + solder_paste_margin = GetTokenDim(&line, true); + } else if (keyword.CmpNoCase(wxT(".SolderPasteRatio")) == 0) { + solder_paste_ratio = GetTokenLong(&line); + } else if (keyword.CmpNoCase(wxT(".ZoneConnection")) == 0) { + zone_connect = GetTokenLong(&line); + } else if (keyword.CmpNoCase(wxT(".ThermalWidth")) == 0) { + thermal_width = GetTokenDim(&line, true); + } else if (keyword.CmpNoCase(wxT(".ThermalGap")) == 0) { + thermal_gap = GetTokenDim(&line, true); + } + } + wxString newline = wxString::Format(wxT("(pad \"%s\" %s %s"), name.c_str(), type.c_str(), shape.c_str()); + if (angle != 0) + newline += wxString::Format(wxT(" (at %.4f %.4f %.1f)"), px, py, angle / 10.0); + else + newline += wxString::Format(wxT(" (at %.4f %.4f)"), px, py); + newline += wxString::Format(wxT(" (size %.4f %.4f)"), pw, ph); + if (!Equal(tx, 0.0) || !Equal(ty, 0.0)) + newline += wxString::Format(wxT(" (rect_delta %.4f %.4f)"), tx, ty); + if ((type.CmpNoCase(wxT("thru_hole")) == 0 || type.CmpNoCase(wxT("np_thru_hole")) == 0) && drillwidth > EPSILON) { + if (Equal(drillwidth, drillheight)) + newline += wxString::Format(wxT(" (drill %.4f (offset %.4f %.4f))"), drillwidth, drillx, drilly); + else + newline += wxString::Format(wxT(" (drill oval %.4f %.4f (offset %.4f %.4f))"), drillwidth, drillheight, drillx, drilly); + } + newline += wxT(" (layers"); + if ((layermask & 0x0000ffff) == 0x0000ffff) { + newline += wxT(" *.Cu"); + layermask &= ~ 0x0000ffff; + } + if ((layermask & 0x00300000) == 0x00300000) { + newline += wxT(" *.Silk"); + layermask &= ~ 0x00300000; + } + if ((layermask & 0x00c00000) == 0x00c00000) { + newline += wxT(" *.Mask"); + layermask &= ~ 0x00c00000; + } + for (long lidx = 0; lidx < 32; lidx++) { + if ((layermask & (1 << lidx)) != 0) { + newline += wxT(" "); + newline += LayerName(lidx); + } + } + newline += wxT(")"); + if (die_length > EPSILON) + newline += wxString::Format(wxT(" (die_length %.4f)"), die_length); + if (solder_mask_margin > EPSILON) + newline += wxString::Format(wxT(" (solder_mask_margin %.4f)"), solder_mask_margin); + if (clearance > EPSILON) + newline += wxString::Format(wxT(" (clearance %.4f)"), clearance); + if (solder_paste_margin > EPSILON) + newline += wxString::Format(wxT(" (solder_paste_margin %.4f)"), solder_paste_margin); + if (solder_paste_ratio >= 0) + newline += wxString::Format(wxT(" (solder_paste_ratio %ld)"), solder_paste_ratio); + if (zone_connect >= 0) + newline += wxString::Format(wxT(" (zone_connect %ld)"), zone_connect); + if (thermal_width > EPSILON) + newline += wxString::Format(wxT(" (thermal_width %.4f)"), thermal_width); + if (thermal_gap > EPSILON) + newline += wxString::Format(wxT(" (thermal_gap %.4f)"), thermal_gap); + newline += wxT(")"); + output->Add(newline); + } else if (keyword.CmpNoCase(wxT("$SHAPE3D")) == 0) { + wxString path = wxEmptyString; + double ox = 0, oy = 0, oz = 0; + double sx = 1, sy = 1, sz = 1; + double rx = 0, ry = 0, rz = 0; + while (idx < module.Count()) { + idx++; + line = module[idx]; + line.Trim(); + if (line.CmpNoCase(wxT("$EndSHAPE3D")) == 0) + break; + keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("Na")) == 0) { + path = line; + if (path[0] != wxT('"')) + path = wxT("\"") + path + wxT("\""); + } else if (keyword.CmpNoCase(wxT("Of")) == 0) { + ox = GetTokenDim(&line, true); + oy = GetTokenDim(&line, true); + oz = GetTokenDim(&line, true); + } else if (keyword.CmpNoCase(wxT("Sc")) == 0) { + sx = GetTokenDim(&line, true); + sy = GetTokenDim(&line, true); + sz = GetTokenDim(&line, true); + } else if (keyword.CmpNoCase(wxT("Ro")) == 0) { + rx = GetTokenDim(&line, true); + ry = GetTokenDim(&line, true); + rz = GetTokenDim(&line, true); + } + } + wxString newline = wxString::Format(wxT("(model %s (at (xyz %.4f %.4f %.4f)) (scale (xyz %.4f %.4f %.4f)) (rotate (xyz %.4f %.4f %.4f)))"), + path.c_str(), ox, oy, oz, sx, sy, sz, rx, ry, rz); + output->Add(newline); + } + } } void TranslateToLegacy(wxArrayString* output, const wxArrayString& module) { - wxASSERT(output != 0); - output->Clear(); - wxString symbolname; - wxString templatename; - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - if (line[0] == '#') { - /* check for a #template comment, to translate this to "AR" */ - if (line.Left(9).CmpNoCase(wxT("#template")) == 0) - templatename = line.Mid(9); - continue; - } - wxString keyword = GetToken(&line); - if (keyword[0] != '(') - continue; - keyword = keyword.Mid(1); - if (keyword.CmpNoCase(wxT("module")) == 0) { - symbolname = GetToken(&line); + wxASSERT(output != 0); + output->Clear(); + wxString symbolname; + wxString templatename; + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + if (line[0] == '#') { + /* check for a #template comment, to translate this to "AR" */ + if (line.Left(9).CmpNoCase(wxT("#template")) == 0) + templatename = line.Mid(9); + continue; + } + wxString keyword = GetToken(&line); + if (keyword[0] != '(') + continue; + keyword = keyword.Mid(1); + if (keyword.CmpNoCase(wxT("module")) == 0) { + symbolname = GetToken(&line); symbolname = symbolname.AfterLast(wxT(':')); - bool islocked = false; - if (line.length() > 0) { - wxString field = GetToken(&line); - if (field.CmpNoCase(wxT("locked")) == 0) - islocked = true; - } - double xpos = 0, ypos = 0, angle = 0; - long layer = -1; - long penalty90 = 0, penalty180 = 0; - unsigned long timestamp = 0; - wxString cmptype = wxT("STD"); - /* get other information needed for the header lines */ - for (unsigned idx2 = idx + 1; idx2 < module.Count(); idx2++) { - wxString line = module[idx]; - wxString keyword = GetToken(&line); - if (keyword[0] != '(') - continue; - keyword = keyword.Mid(1); - if (keyword.CmpNoCase(wxT("layer")) == 0) { - wxString field = GetToken(&line); - layer = LayerNumber(field); - } else if (keyword.CmpNoCase(wxT("at")) == 0) { - xpos = GetTokenDim(&line, true); - ypos = GetTokenDim(&line, true); - if (line.length() > 0) - angle = GetTokenDouble(&line); - } else if (keyword.CmpNoCase(wxT("attr")) == 0) { - wxString field = GetToken(&line); - if (field.CmpNoCase(wxT("smd")) == 0) - cmptype = wxT("SMD"); - } else if (keyword.CmpNoCase(wxT("autoplace_cost90")) == 0) { - penalty90 = GetTokenLong(&line); - } else if (keyword.CmpNoCase(wxT("autoplace_cost180")) == 0) { - penalty180 = GetTokenLong(&line); - } else if (keyword.CmpNoCase(wxT("tedit")) == 0) { - wxString field = GetToken(&line); - field.ToULong(×tamp, 16); - } - } - output->Add(wxT("$MODULE ") + symbolname); - wxString newline = wxString::Format(wxT("Po %.4f %.4f %ld %ld %X 0 "), - xpos, ypos, (long)(angle * 10), - layer, timestamp); - if (islocked) - newline += wxT("F~"); - else - newline += wxT("~~"); - output->Add(newline); - output->Add(wxT("Li ") + symbolname); - output->Add(wxT("At ") + cmptype); - if (penalty90 > 0 || penalty180 > 0) { - newline = wxString::Format(wxT("Op %ld %ld 0"), penalty90, penalty180); - output->Add(newline); - } - if (templatename.Length() > 0) - output->Add(wxT("AR ") + templatename); - } else if (keyword.CmpNoCase(wxT("descr")) == 0) { - wxString field = GetToken(&line); - output->Add(wxT("Cd ") + field); - } else if (keyword.CmpNoCase(wxT("tags")) == 0) { - wxString field = GetToken(&line); - output->Add(wxT("Kw ") + field); - } else if (keyword.CmpNoCase(wxT("fp_text")) == 0) { - wxString field = GetToken(&line); - long texttype = 2; /* assume "user" */ - if (field.CmpNoCase(wxT("reference")) == 0) - texttype = 0; - else if (field.CmpNoCase(wxT("value")) == 0) - texttype = 1; - wxString text = GetToken(&line); - bool ishidden = line.Find(wxT(" hide ")) > 0; - double xpos = 0, ypos = 0, angle = 0; - wxString section = GetSection(line, wxT("at")); - if (section.length() > 0) { - xpos = GetTokenDim(§ion, true); - ypos = GetTokenDim(§ion, true); - if (section.length() > 0) - angle = GetTokenDouble(§ion); - } - long layer = 21; /* assume top silk */ - section = GetSection(line, wxT("layer")); - if (section.length() > 0) { - field = GetToken(§ion); - layer = LayerNumber(field); - } - double width = 1, height = 1, penwidth = 0.1; - section = GetSection(line, wxT("effects")); - if (section.length() > 0) { - section = GetSection(section, wxT("font")); - if (section.length() > 0) { - wxString subsection = GetSection(section, wxT("size")); - if (subsection.length() > 0) { - width = GetTokenDim(&subsection, true); - height = GetTokenDim(&subsection, true); - } - subsection = GetSection(section, wxT("thickness")); - if (subsection.length() > 0) - penwidth = GetTokenDim(&subsection, true); - } - } - wxString newline = wxString::Format(wxT("T%ld %.4f %.4f %.4f %.4f %ld %.4f N %c %ld N \"%s\""), - texttype, xpos, ypos, width, height, - (long)(angle * 10), penwidth, - ishidden ? 'I' : 'V', layer, text.c_str()); - output->Add(newline); - } else if (keyword.CmpNoCase(wxT("fp_line")) == 0) { - double x1 = 0, y1 = 0, x2 = 0, y2 = 0; - wxString section = GetSection(line, wxT("start")); - if (section.length() > 0) { - x1 = GetTokenDim(§ion, true); - y1 = GetTokenDim(§ion, true); - } - section = GetSection(line, wxT("end")); - if (section.length() > 0) { - x2 = GetTokenDim(§ion, true); - y2 = GetTokenDim(§ion, true); - } - double penwidth = 0.1; - section = GetSection(line, wxT("width")); - if (section.length() > 0) - penwidth = GetTokenDim(§ion, true); - long layer = 21; /* assume top silk */ - section = GetSection(line, wxT("layer")); - if (section.length() > 0) { - wxString field = GetToken(§ion); - layer = LayerNumber(field); - } - wxString newline = wxString::Format(wxT("DS %.4f %.4f %.4f %.4f %.4f %ld"), - x1, y1, x2, y2, penwidth, layer); - output->Add(newline); - } else if (keyword.CmpNoCase(wxT("fp_circle")) == 0) { - double xpos = 0, ypos = 0, xpt = 0, ypt = 0; - wxString section = GetSection(line, wxT("center")); - if (section.length() > 0) { - xpos = GetTokenDim(§ion, true); - ypos = GetTokenDim(§ion, true); - } - section = GetSection(line, wxT("end")); - if (section.length() > 0) { - xpt = GetTokenDim(§ion, true); - ypt = GetTokenDim(§ion, true); - } - double penwidth = 0.1; - section = GetSection(line, wxT("width")); - if (section.length() > 0) - penwidth = GetTokenDim(§ion, true); - long layer = 21; /* assume top silk */ - section = GetSection(line, wxT("layer")); - if (section.length() > 0) { - wxString field = GetToken(§ion); - layer = LayerNumber(field); - } - wxString newline = wxString::Format(wxT("DC %.4f %.4f %.4f %.4f %.4f %ld"), - xpos, ypos, xpt, ypt, penwidth, layer); - output->Add(newline); - } else if (keyword.CmpNoCase(wxT("fp_arc")) == 0) { - double xpos = 0, ypos = 0, xpt = 0, ypt = 0; - wxString section = GetSection(line, wxT("start")); - if (section.length() > 0) { - xpos = GetTokenDim(§ion, true); - ypos = GetTokenDim(§ion, true); - } - section = GetSection(line, wxT("end")); - if (section.length() > 0) { - xpt = GetTokenDim(§ion, true); - ypt = GetTokenDim(§ion, true); - } - double angle = 0; - section = GetSection(line, wxT("angle")); - if (section.length() > 0) - angle = GetTokenDim(§ion, true); - double penwidth = 0.1; - section = GetSection(line, wxT("width")); - if (section.length() > 0) - penwidth = GetTokenDim(§ion, true); - long layer = 21; /* assume top silk */ - section = GetSection(line, wxT("layer")); - if (section.length() > 0) { - wxString field = GetToken(§ion); - layer = LayerNumber(field); - } - wxString newline = wxString::Format(wxT("DA %.4f %.4f %.4f %.4f %ld %.4f %ld"), - xpos, ypos, xpt, ypt, (long)(10 * angle), penwidth, layer); - output->Add(newline); - } else if (keyword.CmpNoCase(wxT("fp_poly")) == 0) { - long count = 0; - wxString section = GetSection(line, wxT("pts")); - if (section.Length() > 0) { - while (GetSection(section, wxT("xy"), count).length() > 0) - count++; - } - double penwidth = 0.1; - section = GetSection(line, wxT("width")); - if (section.length() > 0) - penwidth = GetTokenDim(§ion, true); - long layer = 21; /* assume top silk */ - section = GetSection(line, wxT("layer")); - if (section.length() > 0) { - wxString field = GetToken(§ion); - layer = LayerNumber(field); - } - wxString newline = wxString::Format(wxT("DP 0 0 0 0 %ld %.4f %ld"), - count, penwidth, layer); - output->Add(newline); - section = GetSection(line, wxT("pts")); - for (long i = 0; i < count; i++) { - wxString subsect = GetSection(section, wxT("xy"), count); - double x = GetTokenDim(&subsect, true); - double y = GetTokenDim(&subsect, true); - newline = wxString::Format(wxT("Dl %.4f %.4f"), x, y); - output->Add(newline); - } - } else if (keyword.CmpNoCase(wxT("fp_curve")) == 0) { - wxASSERT(0); /* fp_curve cannot be supported (need to convert to DP/Dl in legacy format) */ - } else if (keyword.CmpNoCase(wxT("solder_mask_margin")) == 0) { - double dim = GetTokenDim(&line, true); - wxString newline = wxString::Format(wxT(".SolderMask %.4f"), dim); - output->Add(newline); - } else if (keyword.CmpNoCase(wxT("solder_paste_margin")) == 0) { - double dim = GetTokenDim(&line, true); - wxString newline = wxString::Format(wxT(".SolderPaste %.4f"), dim); - output->Add(newline); - } else if (keyword.CmpNoCase(wxT("solder_paste_ratio")) == 0) { - long dim = GetTokenLong(&line); - wxString newline = wxString::Format(wxT(".SolderPasteRatio %ld"), dim); - output->Add(newline); - } else if (keyword.CmpNoCase(wxT("clearance")) == 0) { - double dim = GetTokenDim(&line, true); - wxString newline = wxString::Format(wxT(".LocalClearance %.4f"), dim); - output->Add(newline); - } else if (keyword.CmpNoCase(wxT("zone_connect")) == 0) { - long dim = GetTokenLong(&line); - wxString newline = wxString::Format(wxT(".ZoneConnection %ld"), dim); - output->Add(newline); - } else if (keyword.CmpNoCase(wxT("thermal_width")) == 0) { - double dim = GetTokenDim(&line, true); - wxString newline = wxString::Format(wxT(".ThermalWidth %.4f"), dim); - output->Add(newline); - } else if (keyword.CmpNoCase(wxT("thermal_gap")) == 0) { - double dim = GetTokenDim(&line, true); - wxString newline = wxString::Format(wxT(".ThermalGap %.4f"), dim); - output->Add(newline); - } else if (keyword.CmpNoCase(wxT("pad")) == 0) { - output->Add(wxT("$PAD")); - wxString name = GetToken(&line); - wxString type = GetToken(&line); - wxString shape = GetToken(&line); - double angle = 0; - wxString section = GetSection(line, wxT("at")); - if (section.Length() > 0) { - double xpos = GetTokenDim(§ion, true); - double ypos = GetTokenDim(§ion, true); - wxString newline = wxString::Format(wxT("Po %.4f %.4f"), xpos, ypos); - output->Add(newline); - if (line.length() > 0) - angle = GetTokenDouble(§ion); - } - section = GetSection(line, wxT("size")); - if (section.Length() > 0) { - double width = GetTokenDim(§ion, true); - double height = GetTokenDim(§ion, true); - char lshape = 'C'; - if (shape.CmpNoCase(wxT("rect")) == 0) - lshape = 'R'; - else if (shape.CmpNoCase(wxT("oval")) == 0) - lshape = 'O'; - else if (shape.CmpNoCase(wxT("trapezoid")) == 0) - lshape = 'T'; - double dx = 0, dy = 0; - section = GetSection(line, wxT("rect_delta")); - if (section.Length() > 0) { - dx = GetTokenDim(§ion, true); - dy = GetTokenDim(§ion, true); - } - wxString newline = wxString::Format(wxT("Sh \"%s\" %c %.4f %.4f %.4f %.4f %ld"), - name.c_str(), lshape, width, height, dx, dy, - (long)(angle * 10)); - output->Add(newline); - } - long mask = 0; - section = GetSection(line, wxT("layers")); - if (section.Length() > 0) { - while (section.length() > 0) { - wxString field = GetToken(§ion); - if (field.CmpNoCase(wxT("*.Cu")) == 0) - mask |= 0x0000ffff; - else if (field.CmpNoCase(wxT("*.Mask")) == 0) - mask |= 0x00c00000; - else if (field.CmpNoCase(wxT("*.Silk")) == 0) - mask |= 0x00300000; - else - mask |= LayerNumber(field); - } - } - if (type.CmpNoCase(wxT("thru_hole")) == 0) - type = wxT("STD"); - else if (type.CmpNoCase(wxT("smd")) == 0) - type = wxT("SMD"); - else if (type.CmpNoCase(wxT("connect")) == 0) - type = wxT("CONN"); - else - type = wxT("HOLE"); - wxString newline = wxString::Format(wxT("At %s N %X"), type.c_str(), mask); - output->Add(newline); - section = GetSection(line, wxT("drill")); - if (section.Length() > 0) { - wxString field = GetToken(§ion); - double width, height; - if (field.CmpNoCase(wxT("oval")) == 0) { - width = GetTokenDim(§ion, true); - height = GetTokenDim(§ion, true); - } else { - field.ToDouble(&width); /* already in mm, so no conversion needed */ - height = width; - } + bool islocked = false; + if (line.length() > 0) { + wxString field = GetToken(&line); + if (field.CmpNoCase(wxT("locked")) == 0) + islocked = true; + } + double xpos = 0, ypos = 0, angle = 0; + long layer = -1; + long penalty90 = 0, penalty180 = 0; + unsigned long timestamp = 0; + wxString cmptype = wxT("STD"); + /* get other information needed for the header lines */ + for (unsigned idx2 = idx + 1; idx2 < module.Count(); idx2++) { + wxString line = module[idx]; + wxString keyword = GetToken(&line); + if (keyword[0] != '(') + continue; + keyword = keyword.Mid(1); + if (keyword.CmpNoCase(wxT("layer")) == 0) { + wxString field = GetToken(&line); + layer = LayerNumber(field); + } else if (keyword.CmpNoCase(wxT("at")) == 0) { + xpos = GetTokenDim(&line, true); + ypos = GetTokenDim(&line, true); + if (line.length() > 0) + angle = GetTokenDouble(&line); + } else if (keyword.CmpNoCase(wxT("attr")) == 0) { + wxString field = GetToken(&line); + if (field.CmpNoCase(wxT("smd")) == 0) + cmptype = wxT("SMD"); + } else if (keyword.CmpNoCase(wxT("autoplace_cost90")) == 0) { + penalty90 = GetTokenLong(&line); + } else if (keyword.CmpNoCase(wxT("autoplace_cost180")) == 0) { + penalty180 = GetTokenLong(&line); + } else if (keyword.CmpNoCase(wxT("tedit")) == 0) { + wxString field = GetToken(&line); + field.ToULong(×tamp, 16); + } + } + output->Add(wxT("$MODULE ") + symbolname); + wxString newline = wxString::Format(wxT("Po %.4f %.4f %ld %ld %X 0 "), + xpos, ypos, (long)(angle * 10), + layer, timestamp); + if (islocked) + newline += wxT("F~"); + else + newline += wxT("~~"); + output->Add(newline); + output->Add(wxT("Li ") + symbolname); + output->Add(wxT("At ") + cmptype); + if (penalty90 > 0 || penalty180 > 0) { + newline = wxString::Format(wxT("Op %ld %ld 0"), penalty90, penalty180); + output->Add(newline); + } + if (templatename.Length() > 0) + output->Add(wxT("AR ") + templatename); + } else if (keyword.CmpNoCase(wxT("descr")) == 0) { + wxString field = GetToken(&line); + output->Add(wxT("Cd ") + field); + } else if (keyword.CmpNoCase(wxT("tags")) == 0) { + wxString field = GetToken(&line); + output->Add(wxT("Kw ") + field); + } else if (keyword.CmpNoCase(wxT("fp_text")) == 0) { + wxString field = GetToken(&line); + long texttype = 2; /* assume "user" */ + if (field.CmpNoCase(wxT("reference")) == 0) + texttype = 0; + else if (field.CmpNoCase(wxT("value")) == 0) + texttype = 1; + wxString text = GetToken(&line); + bool ishidden = line.Find(wxT(" hide ")) > 0; + double xpos = 0, ypos = 0, angle = 0; + wxString section = GetSection(line, wxT("at")); + if (section.length() > 0) { + xpos = GetTokenDim(§ion, true); + ypos = GetTokenDim(§ion, true); + if (section.length() > 0) + angle = GetTokenDouble(§ion); + } + long layer = 21; /* assume top silk */ + section = GetSection(line, wxT("layer")); + if (section.length() > 0) { + field = GetToken(§ion); + layer = LayerNumber(field); + } + double width = 1, height = 1, penwidth = 0.1; + section = GetSection(line, wxT("effects")); + if (section.length() > 0) { + section = GetSection(section, wxT("font")); + if (section.length() > 0) { + wxString subsection = GetSection(section, wxT("size")); + if (subsection.length() > 0) { + width = GetTokenDim(&subsection, true); + height = GetTokenDim(&subsection, true); + } + subsection = GetSection(section, wxT("thickness")); + if (subsection.length() > 0) + penwidth = GetTokenDim(&subsection, true); + } + } + wxString newline = wxString::Format(wxT("T%ld %.4f %.4f %.4f %.4f %ld %.4f N %c %ld N \"%s\""), + texttype, xpos, ypos, width, height, + (long)(angle * 10), penwidth, + ishidden ? 'I' : 'V', layer, text.c_str()); + output->Add(newline); + } else if (keyword.CmpNoCase(wxT("fp_line")) == 0) { + double x1 = 0, y1 = 0, x2 = 0, y2 = 0; + wxString section = GetSection(line, wxT("start")); + if (section.length() > 0) { + x1 = GetTokenDim(§ion, true); + y1 = GetTokenDim(§ion, true); + } + section = GetSection(line, wxT("end")); + if (section.length() > 0) { + x2 = GetTokenDim(§ion, true); + y2 = GetTokenDim(§ion, true); + } + double penwidth = 0.1; + section = GetSection(line, wxT("width")); + if (section.length() > 0) + penwidth = GetTokenDim(§ion, true); + long layer = 21; /* assume top silk */ + section = GetSection(line, wxT("layer")); + if (section.length() > 0) { + wxString field = GetToken(§ion); + layer = LayerNumber(field); + } + wxString newline = wxString::Format(wxT("DS %.4f %.4f %.4f %.4f %.4f %ld"), + x1, y1, x2, y2, penwidth, layer); + output->Add(newline); + } else if (keyword.CmpNoCase(wxT("fp_circle")) == 0) { + double xpos = 0, ypos = 0, xpt = 0, ypt = 0; + wxString section = GetSection(line, wxT("center")); + if (section.length() > 0) { + xpos = GetTokenDim(§ion, true); + ypos = GetTokenDim(§ion, true); + } + section = GetSection(line, wxT("end")); + if (section.length() > 0) { + xpt = GetTokenDim(§ion, true); + ypt = GetTokenDim(§ion, true); + } + double penwidth = 0.1; + section = GetSection(line, wxT("width")); + if (section.length() > 0) + penwidth = GetTokenDim(§ion, true); + long layer = 21; /* assume top silk */ + section = GetSection(line, wxT("layer")); + if (section.length() > 0) { + wxString field = GetToken(§ion); + layer = LayerNumber(field); + } + wxString newline = wxString::Format(wxT("DC %.4f %.4f %.4f %.4f %.4f %ld"), + xpos, ypos, xpt, ypt, penwidth, layer); + output->Add(newline); + } else if (keyword.CmpNoCase(wxT("fp_arc")) == 0) { + double xpos = 0, ypos = 0, xpt = 0, ypt = 0; + wxString section = GetSection(line, wxT("start")); + if (section.length() > 0) { + xpos = GetTokenDim(§ion, true); + ypos = GetTokenDim(§ion, true); + } + section = GetSection(line, wxT("end")); + if (section.length() > 0) { + xpt = GetTokenDim(§ion, true); + ypt = GetTokenDim(§ion, true); + } + double angle = 0; + section = GetSection(line, wxT("angle")); + if (section.length() > 0) + angle = GetTokenDim(§ion, true); + double penwidth = 0.1; + section = GetSection(line, wxT("width")); + if (section.length() > 0) + penwidth = GetTokenDim(§ion, true); + long layer = 21; /* assume top silk */ + section = GetSection(line, wxT("layer")); + if (section.length() > 0) { + wxString field = GetToken(§ion); + layer = LayerNumber(field); + } + wxString newline = wxString::Format(wxT("DA %.4f %.4f %.4f %.4f %ld %.4f %ld"), + xpos, ypos, xpt, ypt, (long)(10 * angle), penwidth, layer); + output->Add(newline); + } else if (keyword.CmpNoCase(wxT("fp_poly")) == 0) { + long count = 0; + wxString section = GetSection(line, wxT("pts")); + if (section.Length() > 0) { + while (GetSection(section, wxT("xy"), count).length() > 0) + count++; + } + double penwidth = 0.1; + section = GetSection(line, wxT("width")); + if (section.length() > 0) + penwidth = GetTokenDim(§ion, true); + long layer = 21; /* assume top silk */ + section = GetSection(line, wxT("layer")); + if (section.length() > 0) { + wxString field = GetToken(§ion); + layer = LayerNumber(field); + } + wxString newline = wxString::Format(wxT("DP 0 0 0 0 %ld %.4f %ld"), + count, penwidth, layer); + output->Add(newline); + section = GetSection(line, wxT("pts")); + for (long i = 0; i < count; i++) { + wxString subsect = GetSection(section, wxT("xy"), count); + double x = GetTokenDim(&subsect, true); + double y = GetTokenDim(&subsect, true); + newline = wxString::Format(wxT("Dl %.4f %.4f"), x, y); + output->Add(newline); + } + } else if (keyword.CmpNoCase(wxT("fp_curve")) == 0) { + wxASSERT(0); /* fp_curve cannot be supported (need to convert to DP/Dl in legacy format) */ + } else if (keyword.CmpNoCase(wxT("solder_mask_margin")) == 0) { + double dim = GetTokenDim(&line, true); + wxString newline = wxString::Format(wxT(".SolderMask %.4f"), dim); + output->Add(newline); + } else if (keyword.CmpNoCase(wxT("solder_paste_margin")) == 0) { + double dim = GetTokenDim(&line, true); + wxString newline = wxString::Format(wxT(".SolderPaste %.4f"), dim); + output->Add(newline); + } else if (keyword.CmpNoCase(wxT("solder_paste_ratio")) == 0) { + long dim = GetTokenLong(&line); + wxString newline = wxString::Format(wxT(".SolderPasteRatio %ld"), dim); + output->Add(newline); + } else if (keyword.CmpNoCase(wxT("clearance")) == 0) { + double dim = GetTokenDim(&line, true); + wxString newline = wxString::Format(wxT(".LocalClearance %.4f"), dim); + output->Add(newline); + } else if (keyword.CmpNoCase(wxT("zone_connect")) == 0) { + long dim = GetTokenLong(&line); + wxString newline = wxString::Format(wxT(".ZoneConnection %ld"), dim); + output->Add(newline); + } else if (keyword.CmpNoCase(wxT("thermal_width")) == 0) { + double dim = GetTokenDim(&line, true); + wxString newline = wxString::Format(wxT(".ThermalWidth %.4f"), dim); + output->Add(newline); + } else if (keyword.CmpNoCase(wxT("thermal_gap")) == 0) { + double dim = GetTokenDim(&line, true); + wxString newline = wxString::Format(wxT(".ThermalGap %.4f"), dim); + output->Add(newline); + } else if (keyword.CmpNoCase(wxT("pad")) == 0) { + output->Add(wxT("$PAD")); + wxString name = GetToken(&line); + wxString type = GetToken(&line); + wxString shape = GetToken(&line); + double angle = 0; + wxString section = GetSection(line, wxT("at")); + if (section.Length() > 0) { + double xpos = GetTokenDim(§ion, true); + double ypos = GetTokenDim(§ion, true); + wxString newline = wxString::Format(wxT("Po %.4f %.4f"), xpos, ypos); + output->Add(newline); + if (line.length() > 0) + angle = GetTokenDouble(§ion); + } + section = GetSection(line, wxT("size")); + if (section.Length() > 0) { + double width = GetTokenDim(§ion, true); + double height = GetTokenDim(§ion, true); + char lshape = 'C'; + if (shape.CmpNoCase(wxT("rect")) == 0) + lshape = 'R'; + else if (shape.CmpNoCase(wxT("oval")) == 0) + lshape = 'O'; + else if (shape.CmpNoCase(wxT("trapezoid")) == 0) + lshape = 'T'; + double dx = 0, dy = 0; + section = GetSection(line, wxT("rect_delta")); + if (section.Length() > 0) { + dx = GetTokenDim(§ion, true); + dy = GetTokenDim(§ion, true); + } + wxString newline = wxString::Format(wxT("Sh \"%s\" %c %.4f %.4f %.4f %.4f %ld"), + name.c_str(), lshape, width, height, dx, dy, + (long)(angle * 10)); + output->Add(newline); + } + long mask = 0; + section = GetSection(line, wxT("layers")); + if (section.Length() > 0) { + while (section.length() > 0) { + wxString field = GetToken(§ion); + if (field.CmpNoCase(wxT("*.Cu")) == 0) + mask |= 0x0000ffff; + else if (field.CmpNoCase(wxT("*.Mask")) == 0) + mask |= 0x00c00000; + else if (field.CmpNoCase(wxT("*.Silk")) == 0) + mask |= 0x00300000; + else + mask |= LayerNumber(field); + } + } + if (type.CmpNoCase(wxT("thru_hole")) == 0) + type = wxT("STD"); + else if (type.CmpNoCase(wxT("smd")) == 0) + type = wxT("SMD"); + else if (type.CmpNoCase(wxT("connect")) == 0) + type = wxT("CONN"); + else + type = wxT("HOLE"); + wxString newline = wxString::Format(wxT("At %s N %X"), type.c_str(), mask); + output->Add(newline); + section = GetSection(line, wxT("drill")); + if (section.Length() > 0) { + wxString field = GetToken(§ion); + double width, height; + if (field.CmpNoCase(wxT("oval")) == 0) { + width = GetTokenDim(§ion, true); + height = GetTokenDim(§ion, true); + } else { + field.ToDouble(&width); /* already in mm, so no conversion needed */ + height = width; + } double xpos = 0, ypos = 0; - section = GetSection(section, wxT("offset")); - if (section.Length() > 0) { - xpos = GetTokenDim(§ion, true); - ypos = GetTokenDim(§ion, true); - } - if (Equal(width, height)) - newline = wxString::Format(wxT("Dr %.4f %.4f %.4f"), width, xpos, ypos); - else - newline = wxString::Format(wxT("Dr %.4f %.4f %.4f O %.4f %.4f"), - min(width, height), xpos, ypos, width, height); - output->Add(newline); - } - section = GetSection(line, wxT("die_length")); - if (section.Length() > 0) { - double dim = GetTokenDim(§ion, true); - newline = wxString::Format(wxT("Le %.4f"), dim); - output->Add(newline); - } - section = GetSection(line, wxT("solder_mask_margin")); - if (section.Length() > 0) { - double dim = GetTokenDim(§ion, true); - newline = wxString::Format(wxT(".SolderMask %.4f"), dim); - output->Add(newline); - } - section = GetSection(line, wxT("clearance")); - if (section.Length() > 0) { - double dim = GetTokenDim(§ion, true); - newline = wxString::Format(wxT(".LocalClearance %.4f"), dim); - output->Add(newline); - } - section = GetSection(line, wxT("solder_paste_margin")); - if (section.Length() > 0) { - double dim = GetTokenDim(§ion, true); - newline = wxString::Format(wxT(".SolderPaste %.4f"), dim); - output->Add(newline); - } - section = GetSection(line, wxT("solder_paste_ratio")); - if (section.Length() > 0) { - long val = GetTokenLong(§ion); - newline = wxString::Format(wxT(".SolderPasteRatio %ld"), val); - output->Add(newline); - } - section = GetSection(line, wxT("zone_connect")); - if (section.Length() > 0) { - long val = GetTokenLong(§ion); - newline = wxString::Format(wxT(".ZoneConnection %ld"), val); - output->Add(newline); - } - section = GetSection(line, wxT("thermal_width")); - if (section.Length() > 0) { - double dim = GetTokenDim(§ion, true); - newline = wxString::Format(wxT(".ThermalWidth %.4f"), dim); - output->Add(newline); - } - section = GetSection(line, wxT("thermal_gap")); - if (section.Length() > 0) { - double dim = GetTokenDim(§ion, true); - newline = wxString::Format(wxT(".ThermalGap %.4f"), dim); - output->Add(newline); - } - output->Add(wxT("$EndPAD")); - } else if (keyword.CmpNoCase(wxT("model")) == 0) { - output->Add(wxT("$SHAPE3D")); - wxString name = GetToken(&line); - output->Add(wxT("Na ") + name); - wxString section = GetSection(line, wxT("at")); - if (section.Length() > 0) { - section = GetSection(section, wxT("xyz")); - if (section.Length() > 0) { - double x = GetTokenDim(§ion, true); - double y = GetTokenDim(§ion, true); - double z = GetTokenDim(§ion, true); - wxString newline = wxString::Format(wxT("Of %.4f %.4f %.4f"), x, y, z); - output->Add(newline); - } - } - section = GetSection(line, wxT("scale")); - if (section.Length() > 0) { - section = GetSection(section, wxT("xyz")); - if (section.Length() > 0) { - double x = GetTokenDim(§ion, true); - double y = GetTokenDim(§ion, true); - double z = GetTokenDim(§ion, true); - wxString newline = wxString::Format(wxT("Sc %.4f %.4f %.4f"), x, y, z); - output->Add(newline); - } - } - section = GetSection(line, wxT("rotate")); - if (section.Length() > 0) { - section = GetSection(section, wxT("xyz")); - if (section.Length() > 0) { - double x = GetTokenDim(§ion, true); - double y = GetTokenDim(§ion, true); - double z = GetTokenDim(§ion, true); - wxString newline = wxString::Format(wxT("Ro %.4f %.4f %.4f"), x, y, z); - output->Add(newline); - } - } - output->Add(wxT("$EndSHAPE3D")); - } - } - if (output->Count() > 0) - output->Add(wxT("$EndMODULE ") + symbolname); + section = GetSection(section, wxT("offset")); + if (section.Length() > 0) { + xpos = GetTokenDim(§ion, true); + ypos = GetTokenDim(§ion, true); + } + if (Equal(width, height)) + newline = wxString::Format(wxT("Dr %.4f %.4f %.4f"), width, xpos, ypos); + else + newline = wxString::Format(wxT("Dr %.4f %.4f %.4f O %.4f %.4f"), + min(width, height), xpos, ypos, width, height); + output->Add(newline); + } + section = GetSection(line, wxT("die_length")); + if (section.Length() > 0) { + double dim = GetTokenDim(§ion, true); + newline = wxString::Format(wxT("Le %.4f"), dim); + output->Add(newline); + } + section = GetSection(line, wxT("solder_mask_margin")); + if (section.Length() > 0) { + double dim = GetTokenDim(§ion, true); + newline = wxString::Format(wxT(".SolderMask %.4f"), dim); + output->Add(newline); + } + section = GetSection(line, wxT("clearance")); + if (section.Length() > 0) { + double dim = GetTokenDim(§ion, true); + newline = wxString::Format(wxT(".LocalClearance %.4f"), dim); + output->Add(newline); + } + section = GetSection(line, wxT("solder_paste_margin")); + if (section.Length() > 0) { + double dim = GetTokenDim(§ion, true); + newline = wxString::Format(wxT(".SolderPaste %.4f"), dim); + output->Add(newline); + } + section = GetSection(line, wxT("solder_paste_ratio")); + if (section.Length() > 0) { + long val = GetTokenLong(§ion); + newline = wxString::Format(wxT(".SolderPasteRatio %ld"), val); + output->Add(newline); + } + section = GetSection(line, wxT("zone_connect")); + if (section.Length() > 0) { + long val = GetTokenLong(§ion); + newline = wxString::Format(wxT(".ZoneConnection %ld"), val); + output->Add(newline); + } + section = GetSection(line, wxT("thermal_width")); + if (section.Length() > 0) { + double dim = GetTokenDim(§ion, true); + newline = wxString::Format(wxT(".ThermalWidth %.4f"), dim); + output->Add(newline); + } + section = GetSection(line, wxT("thermal_gap")); + if (section.Length() > 0) { + double dim = GetTokenDim(§ion, true); + newline = wxString::Format(wxT(".ThermalGap %.4f"), dim); + output->Add(newline); + } + output->Add(wxT("$EndPAD")); + } else if (keyword.CmpNoCase(wxT("model")) == 0) { + output->Add(wxT("$SHAPE3D")); + wxString name = GetToken(&line); + output->Add(wxT("Na ") + name); + wxString section = GetSection(line, wxT("at")); + if (section.Length() > 0) { + section = GetSection(section, wxT("xyz")); + if (section.Length() > 0) { + double x = GetTokenDim(§ion, true); + double y = GetTokenDim(§ion, true); + double z = GetTokenDim(§ion, true); + wxString newline = wxString::Format(wxT("Of %.4f %.4f %.4f"), x, y, z); + output->Add(newline); + } + } + section = GetSection(line, wxT("scale")); + if (section.Length() > 0) { + section = GetSection(section, wxT("xyz")); + if (section.Length() > 0) { + double x = GetTokenDim(§ion, true); + double y = GetTokenDim(§ion, true); + double z = GetTokenDim(§ion, true); + wxString newline = wxString::Format(wxT("Sc %.4f %.4f %.4f"), x, y, z); + output->Add(newline); + } + } + section = GetSection(line, wxT("rotate")); + if (section.Length() > 0) { + section = GetSection(section, wxT("xyz")); + if (section.Length() > 0) { + double x = GetTokenDim(§ion, true); + double y = GetTokenDim(§ion, true); + double z = GetTokenDim(§ion, true); + wxString newline = wxString::Format(wxT("Ro %.4f %.4f %.4f"), x, y, z); + output->Add(newline); + } + } + output->Add(wxT("$EndSHAPE3D")); + } + } + if (output->Count() > 0) + output->Add(wxT("$EndMODULE ") + symbolname); } int AdjustPad(wxArrayString& module, FootprintInfo* current, const FootprintInfo& adjusted) { - wxASSERT(current != NULL); - - wxString padshape_adj = wxEmptyString; /* new pad shape name (s-expressions) */ - switch (adjusted.PadShape) { - case 'C': - case 'S': - padshape_adj = wxT("circle"); - break; - case 'O': - padshape_adj = wxT("oval"); - break; - case 'R': - padshape_adj = wxT("rect"); - break; - case 'T': - padshape_adj = wxT("trapezoid"); - break; - } - - CoordPair padsize; - char padshape = '\0'; /* pad shape letter for legacy modules */ - wxString padshape_s = wxEmptyString; /* pad shape name for the s-expressions */ + wxASSERT(current != NULL); + + wxString padshape_adj = wxEmptyString; /* new pad shape name (s-expressions) */ + switch (adjusted.PadShape) { + case 'C': + case 'S': + padshape_adj = wxT("circle"); + break; + case 'O': + padshape_adj = wxT("oval"); + break; + case 'R': + padshape_adj = wxT("rect"); + break; + case 'T': + padshape_adj = wxT("trapezoid"); + break; + } + + CoordPair padsize; + char padshape = '\0'; /* pad shape letter for legacy modules */ + wxString padshape_s = wxEmptyString; /* pad shape name for the s-expressions */ bool all_pads_smd = true; /* if all pads are SMD, the module is marked SMD too */ bool footprint_smd = false; unsigned footprint_attr_line = -1; - double drillsize = 0; - long pinnr = 0; - unsigned Start = 0; - - int Matches = 0; - bool inpad = false; - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - wxString keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("$PAD")) == 0) { - inpad = true; - Start = idx; /* save the position where this pad starts, because - on a match, it must be reparsed */ - } else if (keyword.CmpNoCase(wxT("$EndPAD")) == 0) { - wxASSERT(Start > 0); - wxASSERT(inpad); - if (pinnr > 0 && padshape == current->PadShape && padsize.Equal(current->PadSize[0], TOLERANCE) - && (drillsize > current->DrillSize - TOLERANCE && drillsize < current->DrillSize + TOLERANCE)) - { - /* this pad matches the primary pad, go through it again, to adjust it */ - for (unsigned i = Start; i < module.Count(); i++) { - wxString line = module[i]; - wxString keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("$EndPAD")) == 0) - break; - if (keyword.CmpNoCase(wxT("Sh")) == 0) { - wxString name = GetToken(&line); - GetToken(&line); /* ignore shape */ - GetToken(&line); /* ignore width */ - GetToken(&line); /* ignore height */ - double xdelta = GetTokenDim(&line, true); - double ydelta = GetTokenDim(&line, true); - long rot = GetTokenLong(&line); - padshape = adjusted.PadShape; - if (padshape == 'S') - padshape = (pinnr == 1) ? 'R' : 'C'; - padsize.Set(adjusted.PadSize[0].GetX(), adjusted.PadSize[0].GetY()); - module[i] = wxString::Format(wxT("%s \"%s\" %c %.4f %.4f %.4f %.4f %ld"), - keyword.c_str(), name.c_str(), padshape, - MM(padsize.GetX()), MM(padsize.GetY()), - MM(xdelta), MM(ydelta), rot); - } else if (keyword.CmpNoCase(wxT("Dr")) == 0) { - GetToken(&line); /* ignore drill size */ - double xpos = GetTokenDim(&line, true); - double ypos = GetTokenDim(&line, true); - drillsize = adjusted.DrillSize; - module[i] = wxString::Format(wxT("%s %.4f %.4f %.4f"), - keyword.c_str(), MM(drillsize), - MM(xpos), MM(ypos)); - } else if (keyword.CmpNoCase(wxT("At")) == 0) { - wxString type = GetToken(&line); - if (type.CmpNoCase(wxT("STD")) == 0 && adjusted.DrillSize < EPSILON) - module[i] = wxT("At SMD N 00888000"); - else if (type.CmpNoCase(wxT("SMD")) == 0 && adjusted.DrillSize > EPSILON) - module[i] = wxT("At STD N 00E0FFFF"); - } - } + double drillsize = 0; + long pinnr = 0; + unsigned Start = 0; + + int Matches = 0; + bool inpad = false; + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + wxString keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("$PAD")) == 0) { + inpad = true; + Start = idx; /* save the position where this pad starts, because + on a match, it must be reparsed */ + } else if (keyword.CmpNoCase(wxT("$EndPAD")) == 0) { + wxASSERT(Start > 0); + wxASSERT(inpad); + if (pinnr > 0 && padshape == current->PadShape && padsize.Equal(current->PadSize[0], TOLERANCE) + && (drillsize > current->DrillSize - TOLERANCE && drillsize < current->DrillSize + TOLERANCE)) + { + /* this pad matches the primary pad, go through it again, to adjust it */ + for (unsigned i = Start; i < module.Count(); i++) { + wxString line = module[i]; + wxString keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("$EndPAD")) == 0) + break; + if (keyword.CmpNoCase(wxT("Sh")) == 0) { + wxString name = GetToken(&line); + GetToken(&line); /* ignore shape */ + GetToken(&line); /* ignore width */ + GetToken(&line); /* ignore height */ + double xdelta = GetTokenDim(&line, true); + double ydelta = GetTokenDim(&line, true); + long rot = GetTokenLong(&line); + padshape = adjusted.PadShape; + if (padshape == 'S') + padshape = (pinnr == 1) ? 'R' : 'C'; + padsize.Set(adjusted.PadSize[0].GetX(), adjusted.PadSize[0].GetY()); + module[i] = wxString::Format(wxT("%s \"%s\" %c %.4f %.4f %.4f %.4f %ld"), + keyword.c_str(), name.c_str(), padshape, + MM(padsize.GetX()), MM(padsize.GetY()), + MM(xdelta), MM(ydelta), rot); + } else if (keyword.CmpNoCase(wxT("Dr")) == 0) { + GetToken(&line); /* ignore drill size */ + double xpos = GetTokenDim(&line, true); + double ypos = GetTokenDim(&line, true); + drillsize = adjusted.DrillSize; + module[i] = wxString::Format(wxT("%s %.4f %.4f %.4f"), + keyword.c_str(), MM(drillsize), + MM(xpos), MM(ypos)); + } else if (keyword.CmpNoCase(wxT("At")) == 0) { + wxString type = GetToken(&line); + if (type.CmpNoCase(wxT("STD")) == 0 && adjusted.DrillSize < EPSILON) + module[i] = wxT("At SMD N 00888000"); + else if (type.CmpNoCase(wxT("SMD")) == 0 && adjusted.DrillSize > EPSILON) + module[i] = wxT("At STD N 00E0FFFF"); + } + } all_pads_smd = all_pads_smd && (drillsize > EPSILON); - Matches++; - } else if (pinnr > 0 && padshape == 'R' && drillsize < EPSILON - && padsize.Equal(current->PadSize[1], TOLERANCE)) - { - /* this pad matches the secondary pad, go through it again, to adjust it */ - for (unsigned i = Start; i < module.Count(); i++) { - wxString line = module[i]; - wxString keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("$EndPAD")) == 0) - break; - if (keyword.CmpNoCase(wxT("Sh")) == 0) { - wxString name = GetToken(&line); - wxString shape = GetToken(&line); - GetToken(&line); /* ignore width */ - GetToken(&line); /* ignore height */ - double xdelta = GetTokenDim(&line, true); - double ydelta = GetTokenDim(&line, true); - long rot = GetTokenLong(&line); - if (padsize.Equal(current->PadSize[1], 0.01)) - padsize.Set(adjusted.PadSize[1].GetX(), adjusted.PadSize[1].GetY()); - else - padsize.Set(adjusted.PadSize[1].GetY(), adjusted.PadSize[1].GetX()); - module[i] = wxString::Format(wxT("%s \"%s\" %c %.4f %.4f %.4f %.4f %ld"), - keyword.c_str(), name.c_str(), shape[0], - MM(padsize.GetX()), MM(padsize.GetY()), - MM(xdelta), MM(ydelta), rot); - } - } - Matches++; - } - padsize.Set(0, 0); - padshape = '\0'; - drillsize = 0; - pinnr = 0; - inpad = false; - } else if (keyword.CmpNoCase(wxT("Sh")) == 0 && inpad) { - wxString field = GetToken(&line); - pinnr = GetPadNumber(field, ¤t->MtxWidth, ¤t->MtxHeight); - field = GetToken(&line); - padshape = field[0]; - if (current->PadShape == 'S' - && ((padshape == 'R' && pinnr == 1) - || (padshape == 'C' && pinnr > 1))) - padshape = 'S'; - double width = GetTokenDim(&line, true); - double height = GetTokenDim(&line, true); - padsize.Set(width, height); - } else if (keyword.CmpNoCase(wxT("Dr")) == 0 && inpad) { - drillsize = GetTokenDim(&line, true); - } else if (keyword.CmpNoCase(wxT("At")) == 0 && !inpad) { - wxString type = GetToken(&line); + Matches++; + } else if (pinnr > 0 && padshape == 'R' && drillsize < EPSILON + && padsize.Equal(current->PadSize[1], TOLERANCE)) + { + /* this pad matches the secondary pad, go through it again, to adjust it */ + for (unsigned i = Start; i < module.Count(); i++) { + wxString line = module[i]; + wxString keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("$EndPAD")) == 0) + break; + if (keyword.CmpNoCase(wxT("Sh")) == 0) { + wxString name = GetToken(&line); + wxString shape = GetToken(&line); + GetToken(&line); /* ignore width */ + GetToken(&line); /* ignore height */ + double xdelta = GetTokenDim(&line, true); + double ydelta = GetTokenDim(&line, true); + long rot = GetTokenLong(&line); + if (padsize.Equal(current->PadSize[1], 0.01)) + padsize.Set(adjusted.PadSize[1].GetX(), adjusted.PadSize[1].GetY()); + else + padsize.Set(adjusted.PadSize[1].GetY(), adjusted.PadSize[1].GetX()); + module[i] = wxString::Format(wxT("%s \"%s\" %c %.4f %.4f %.4f %.4f %ld"), + keyword.c_str(), name.c_str(), shape[0], + MM(padsize.GetX()), MM(padsize.GetY()), + MM(xdelta), MM(ydelta), rot); + } + } + Matches++; + } + padsize.Set(0, 0); + padshape = '\0'; + drillsize = 0; + pinnr = 0; + inpad = false; + } else if (keyword.CmpNoCase(wxT("Sh")) == 0 && inpad) { + wxString field = GetToken(&line); + pinnr = GetPadNumber(field, ¤t->MtxWidth, ¤t->MtxHeight); + field = GetToken(&line); + padshape = field[0]; + if (current->PadShape == 'S' + && ((padshape == 'R' && pinnr == 1) + || (padshape == 'C' && pinnr > 1))) + padshape = 'S'; + double width = GetTokenDim(&line, true); + double height = GetTokenDim(&line, true); + padsize.Set(width, height); + } else if (keyword.CmpNoCase(wxT("Dr")) == 0 && inpad) { + drillsize = GetTokenDim(&line, true); + } else if (keyword.CmpNoCase(wxT("At")) == 0 && !inpad) { + wxString type = GetToken(&line); footprint_smd = (type.CmpNoCase(wxT("SMD")) == 0); footprint_attr_line = idx; - } else if (keyword.CmpNoCase(wxT("(pad")) == 0) { - /* first parse the pad information */ - wxString field = GetToken(&line); - pinnr = GetPadNumber(field, ¤t->MtxWidth, ¤t->MtxHeight); - GetToken(&line); /* ignore smd/thru_hole/np_thru_hole type */ - padshape_s = GetToken(&line); - if (padshape_s.Cmp(wxT("circle")) == 0) - padshape = (current->PadShape == 'S' && pinnr > 1) ? 'S' : 'C'; - else if (padshape_s.Cmp(wxT("rect")) == 0) - padshape = (current->PadShape == 'S' && pinnr == 1) ? 'S' : 'R'; - else if (padshape_s.Cmp(wxT("oval")) == 0) - padshape = 'O'; - else if (padshape_s.Cmp(wxT("trapezoid")) == 0) - padshape = 'T'; - wxString section = GetSection(line, wxT("size")); - if (section.length() > 0) { - double width = GetTokenDim(§ion, true); - double height = GetTokenDim(§ion, true); - padsize.Set(width, height); - } - section = GetSection(line, wxT("drill")); - if (section.length() > 0) { - if (section.Left(4).Cmp(wxT("oval"))==0) - pinnr = 0; /* oval holes are not supported for editing */ - else - drillsize = GetTokenDim(§ion, true); - } - /* adjust the information */ - wxString line = module[idx]; /* get the unmodified line again */ - if (pinnr > 0 && padshape == current->PadShape && padsize.Equal(current->PadSize[0], TOLERANCE) - && (drillsize > current->DrillSize - TOLERANCE && drillsize < current->DrillSize + TOLERANCE)) - { - /* this pad matches the primary pad, adjust it */ - section = wxString::Format(wxT("%.4f %.4f"), MM(adjusted.PadSize[0].GetX()), MM(adjusted.PadSize[0].GetY())); - SetSection(line, wxT("size"), section); + } else if (keyword.CmpNoCase(wxT("(pad")) == 0) { + /* first parse the pad information */ + wxString field = GetToken(&line); + pinnr = GetPadNumber(field, ¤t->MtxWidth, ¤t->MtxHeight); + GetToken(&line); /* ignore smd/thru_hole/np_thru_hole type */ + padshape_s = GetToken(&line); + if (padshape_s.Cmp(wxT("circle")) == 0) + padshape = (current->PadShape == 'S' && pinnr > 1) ? 'S' : 'C'; + else if (padshape_s.Cmp(wxT("rect")) == 0) + padshape = (current->PadShape == 'S' && pinnr == 1) ? 'S' : 'R'; + else if (padshape_s.Cmp(wxT("oval")) == 0) + padshape = 'O'; + else if (padshape_s.Cmp(wxT("trapezoid")) == 0) + padshape = 'T'; + wxString section = GetSection(line, wxT("size")); + if (section.length() > 0) { + double width = GetTokenDim(§ion, true); + double height = GetTokenDim(§ion, true); + padsize.Set(width, height); + } + section = GetSection(line, wxT("drill")); + if (section.length() > 0) { + if (section.Left(4).Cmp(wxT("oval"))==0) + pinnr = 0; /* oval holes are not supported for editing */ + else + drillsize = GetTokenDim(§ion, true); + } + /* adjust the information */ + wxString line = module[idx]; /* get the unmodified line again */ + if (pinnr > 0 && padshape == current->PadShape && padsize.Equal(current->PadSize[0], TOLERANCE) + && (drillsize > current->DrillSize - TOLERANCE && drillsize < current->DrillSize + TOLERANCE)) + { + /* this pad matches the primary pad, adjust it */ + section = wxString::Format(wxT("%.4f %.4f"), MM(adjusted.PadSize[0].GetX()), MM(adjusted.PadSize[0].GetY())); + SetSection(line, wxT("size"), section); if (adjusted.DrillSize > EPSILON) { - section = wxString::Format(wxT("%.4f"), MM(adjusted.DrillSize)); - SetSection(line, wxT("drill"), section); //??? this fails if there is no drill section yet (a new section must be inserted) + section = wxString::Format(wxT("%.4f"), MM(adjusted.DrillSize)); + SetSection(line, wxT("drill"), section); //??? this fails if there is no drill section yet (a new section must be inserted) } else { DeleteSection(line, wxT("drill")); } - if (adjusted.PadShape == 'S' && pinnr == 1) - line.Replace(padshape_s, wxT("rect"), false); - else - line.Replace(padshape_s, padshape_adj, false); - module[idx] = line; + if (adjusted.PadShape == 'S' && pinnr == 1) + line.Replace(padshape_s, wxT("rect"), false); + else + line.Replace(padshape_s, padshape_adj, false); + module[idx] = line; all_pads_smd = all_pads_smd && (drillsize > EPSILON); Matches++; - } else if (pinnr > 0 && padshape == 'R' && drillsize < EPSILON - && padsize.Equal(current->PadSize[1], TOLERANCE)) - { - /* this pad matches the secondary pad, adjust it */ - if (padsize.Equal(current->PadSize[1], 0.01)) - padsize.Set(adjusted.PadSize[1].GetX(), adjusted.PadSize[1].GetY()); - else - padsize.Set(adjusted.PadSize[1].GetY(), adjusted.PadSize[1].GetX()); - section = wxString::Format(wxT("%.4f %.4f"), MM(padsize.GetX()), MM(padsize.GetY())); - SetSection(line, wxT("size"), section); - module[idx] = line; + } else if (pinnr > 0 && padshape == 'R' && drillsize < EPSILON + && padsize.Equal(current->PadSize[1], TOLERANCE)) + { + /* this pad matches the secondary pad, adjust it */ + if (padsize.Equal(current->PadSize[1], 0.01)) + padsize.Set(adjusted.PadSize[1].GetX(), adjusted.PadSize[1].GetY()); + else + padsize.Set(adjusted.PadSize[1].GetY(), adjusted.PadSize[1].GetX()); + section = wxString::Format(wxT("%.4f %.4f"), MM(padsize.GetX()), MM(padsize.GetY())); + SetSection(line, wxT("size"), section); + module[idx] = line; Matches++; - } - padsize.Set(0, 0); - padshape = '\0'; - padshape_s = wxEmptyString; - drillsize = 0; - pinnr = 0; - } else if (keyword.CmpNoCase(wxT("(attr")) == 0) { - wxString type = GetToken(&line); + } + padsize.Set(0, 0); + padshape = '\0'; + padshape_s = wxEmptyString; + drillsize = 0; + pinnr = 0; + } else if (keyword.CmpNoCase(wxT("(attr")) == 0) { + wxString type = GetToken(&line); footprint_smd = (type.CmpNoCase(wxT("smd")) == 0); footprint_attr_line = idx; - } - } + } + } if (all_pads_smd && !footprint_smd) { /* set the module attribute to SMD, first find out the type */ int type = VER_INVALID; unsigned idx; for (idx = 0; type == VER_INVALID && idx < module.Count(); idx++) { - wxString line = module[0]; /* check whether this is s-exprssion or legacy */ + wxString line = module[0]; /* check whether this is s-exprssion or legacy */ wxString keyword = GetToken(&line); if (keyword.CmpNoCase(wxT("(module")) == 0) type = VER_S_EXPR; @@ -1653,554 +1653,554 @@ int AdjustPad(wxArrayString& module, FootprintInfo* current, const FootprintInfo module.Insert(wxT(""), footprint_attr_line); } wxASSERT(footprint_attr_line >= 0 && footprint_attr_line < module.Count()); - if (type == VER_S_EXPR) + if (type == VER_S_EXPR) module[footprint_attr_line] = wxT("(attr smd)"); else module[footprint_attr_line] = wxT("At SMD"); } - /* the module data was adjusted in-place, now also copy the pad/shape - information structure back */ - *current = adjusted; + /* the module data was adjusted in-place, now also copy the pad/shape + information structure back */ + *current = adjusted; - return Matches; + return Matches; } /** AdjustPitchHor() changes the horizontal pitch of a range of pins. - * \param module The footprint data. - * \param firstpin The pin number of the first pin to adjust. - * \param lastpin The pin number of the last pin to adjust. - * \param sequence The value to add to get to each next pin (usually 1). - * \param ymatch The Y-coordinate for the horizontal row that the pads - * should be on. - * \param pitch The new pitch. + * \param module The footprint data. + * \param firstpin The pin number of the first pin to adjust. + * \param lastpin The pin number of the last pin to adjust. + * \param sequence The value to add to get to each next pin (usually 1). + * \param ymatch The Y-coordinate for the horizontal row that the pads + * should be on. + * \param pitch The new pitch. */ int AdjustPitchHor(wxArrayString& module, int firstpin, int lastpin, int sequence, double ymatch, double pitch) { - int Matches = 0; - unsigned Start = 0; - long pinnr = 0; - bool inpad = false; - wxASSERT(sequence >= 1); - long range = (lastpin - firstpin) / sequence; - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - wxString keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("$PAD")) == 0) { - inpad = true; - Start = idx; /* save the position where this pad starts, because - on a match, it must be reparsed */ - } else if (keyword.CmpNoCase(wxT("$EndPAD")) == 0) { - wxASSERT(Start > 0); - wxASSERT(inpad); - bool matchpin = (pinnr >= firstpin && pinnr <= lastpin); - if (matchpin && sequence > 1) - matchpin = matchpin && ((pinnr - firstpin) % sequence) == 0; - if (matchpin) { - /* this pad matches, go through it again, to adjust it */ - for (unsigned i = Start; i < module.Count(); i++) { - wxString line = module[i]; - wxString keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("$EndPAD")) == 0) - break; - if (keyword.CmpNoCase(wxT("Po")) == 0) { - double xpos = GetTokenDim(&line, true); - double ypos = GetTokenDim(&line, true); - if (Equal(ypos, ymatch, 0.02)) { - xpos = pitch * ((pinnr - firstpin) / sequence - range / 2.0); - module[i] = wxString::Format(wxT("%s %.4f %.4f"), keyword.c_str(), MM(xpos), MM(ypos)); - Matches++; - } - } - } - } - inpad = false; - pinnr = 0; - Start = 0; - } else if (keyword.CmpNoCase(wxT("Sh")) == 0 && inpad) { - wxString field = GetToken(&line); - field.ToLong(&pinnr); - } else if (keyword.CmpNoCase(wxT("(pad")) == 0) { - /* first check the pin number */ - wxString field = GetToken(&line); - field.ToLong(&pinnr); - bool matchpin = (pinnr >= firstpin && pinnr <= lastpin); - if (matchpin && sequence > 1) - matchpin = matchpin && ((pinnr - firstpin) % sequence) == 0; - if (matchpin) { - /* this pad matches, adjust it */ - wxString section = GetSection(line, wxT("at")); - if (section.length() > 0) { - double xpos = GetTokenDim(§ion, true); - double ypos = GetTokenDim(§ion, true); - if (Equal(ypos, ymatch, 0.02)) { - xpos = pitch * ((pinnr - firstpin) / sequence - range / 2.0); - if (section.length() > 0) { - double rot = GetTokenDouble(§ion); - section = wxString::Format(wxT("%.4f %.4f %.1f"), MM(xpos), MM(ypos), rot); - } else { - section = wxString::Format(wxT("%.4f %.4f"), MM(xpos), MM(ypos)); - } - line = module[idx]; - SetSection(line, wxT("at"), section); - module[idx] = line; - Matches++; - } - } - } - pinnr = 0; - } - } - return Matches; + int Matches = 0; + unsigned Start = 0; + long pinnr = 0; + bool inpad = false; + wxASSERT(sequence >= 1); + long range = (lastpin - firstpin) / sequence; + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + wxString keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("$PAD")) == 0) { + inpad = true; + Start = idx; /* save the position where this pad starts, because + on a match, it must be reparsed */ + } else if (keyword.CmpNoCase(wxT("$EndPAD")) == 0) { + wxASSERT(Start > 0); + wxASSERT(inpad); + bool matchpin = (pinnr >= firstpin && pinnr <= lastpin); + if (matchpin && sequence > 1) + matchpin = matchpin && ((pinnr - firstpin) % sequence) == 0; + if (matchpin) { + /* this pad matches, go through it again, to adjust it */ + for (unsigned i = Start; i < module.Count(); i++) { + wxString line = module[i]; + wxString keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("$EndPAD")) == 0) + break; + if (keyword.CmpNoCase(wxT("Po")) == 0) { + double xpos = GetTokenDim(&line, true); + double ypos = GetTokenDim(&line, true); + if (Equal(ypos, ymatch, 0.02)) { + xpos = pitch * ((pinnr - firstpin) / sequence - range / 2.0); + module[i] = wxString::Format(wxT("%s %.4f %.4f"), keyword.c_str(), MM(xpos), MM(ypos)); + Matches++; + } + } + } + } + inpad = false; + pinnr = 0; + Start = 0; + } else if (keyword.CmpNoCase(wxT("Sh")) == 0 && inpad) { + wxString field = GetToken(&line); + field.ToLong(&pinnr); + } else if (keyword.CmpNoCase(wxT("(pad")) == 0) { + /* first check the pin number */ + wxString field = GetToken(&line); + field.ToLong(&pinnr); + bool matchpin = (pinnr >= firstpin && pinnr <= lastpin); + if (matchpin && sequence > 1) + matchpin = matchpin && ((pinnr - firstpin) % sequence) == 0; + if (matchpin) { + /* this pad matches, adjust it */ + wxString section = GetSection(line, wxT("at")); + if (section.length() > 0) { + double xpos = GetTokenDim(§ion, true); + double ypos = GetTokenDim(§ion, true); + if (Equal(ypos, ymatch, 0.02)) { + xpos = pitch * ((pinnr - firstpin) / sequence - range / 2.0); + if (section.length() > 0) { + double rot = GetTokenDouble(§ion); + section = wxString::Format(wxT("%.4f %.4f %.1f"), MM(xpos), MM(ypos), rot); + } else { + section = wxString::Format(wxT("%.4f %.4f"), MM(xpos), MM(ypos)); + } + line = module[idx]; + SetSection(line, wxT("at"), section); + module[idx] = line; + Matches++; + } + } + } + pinnr = 0; + } + } + return Matches; } /** AdjustPitchVer() changes the vertical pitch of a range of pins. - * \param module The footprint data. - * \param firstpin The pin number of the first pin to adjust. - * \param lastpin The pin number of the last pin to adjust. - * \param sequence The value to add to get to each next pin (usually 1). - * \param xmatch The X-coordinate for the verticalal row that the pads - * should be on. - * \param pitch The new pitch. + * \param module The footprint data. + * \param firstpin The pin number of the first pin to adjust. + * \param lastpin The pin number of the last pin to adjust. + * \param sequence The value to add to get to each next pin (usually 1). + * \param xmatch The X-coordinate for the verticalal row that the pads + * should be on. + * \param pitch The new pitch. */ int AdjustPitchVer(wxArrayString& module, int firstpin, int lastpin, int sequence, double xmatch, double pitch) { - int Matches = 0; - unsigned Start = 0; - long pinnr = 0; - bool inpad = false; - wxASSERT(sequence >= 1); - long range = (lastpin - firstpin) / sequence; - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - wxString keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("$PAD")) == 0) { - inpad = true; - Start = idx; /* save the position where this pad starts, because - on a match, it must be reparsed */ - } else if (keyword.CmpNoCase(wxT("$EndPAD")) == 0) { - wxASSERT(Start > 0); - wxASSERT(inpad); - bool matchpin = (pinnr >= firstpin && pinnr <= lastpin); - if (matchpin && sequence > 1) - matchpin = matchpin && ((pinnr - firstpin) % sequence) == 0; - if (matchpin) { - /* this pad matches, go through it again, to adjust it */ - for (unsigned i = Start; i < module.Count(); i++) { - wxString line = module[i]; - wxString keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("$EndPAD")) == 0) - break; - if (keyword.CmpNoCase(wxT("Po")) == 0) { - double xpos = GetTokenDim(&line, true); - double ypos = GetTokenDim(&line, true); - if (Equal(xpos, xmatch, 0.02)) { - ypos = pitch * ((pinnr - firstpin) / sequence - range / 2.0); - module[i] = wxString::Format(wxT("%s %.4f %.4f"), keyword.c_str(), MM(xpos), MM(ypos)); - Matches++; - } - } - } - } - inpad = false; - pinnr = 0; - Start = 0; - } else if (keyword.CmpNoCase(wxT("Sh")) == 0 && inpad) { - wxString field = GetToken(&line); - field.ToLong(&pinnr); - } else if (keyword.CmpNoCase(wxT("(pad")) == 0) { - /* first check the pin number */ - wxString field = GetToken(&line); - field.ToLong(&pinnr); - bool matchpin = (pinnr >= firstpin && pinnr <= lastpin); - if (matchpin && sequence > 1) - matchpin = matchpin && ((pinnr - firstpin) % sequence) == 0; - if (matchpin) { - /* this pad matches, adjust it */ - wxString section = GetSection(line, wxT("at")); - if (section.length() > 0) { - double xpos = GetTokenDim(§ion, true); - double ypos = GetTokenDim(§ion, true); - if (Equal(xpos, xmatch, 0.02)) { - ypos = pitch * ((pinnr - firstpin) / sequence - range / 2.0); - if (section.length() > 0) { - double rot = GetTokenDouble(§ion); - section = wxString::Format(wxT("%.4f %.4f %.1f"), MM(xpos), MM(ypos), rot); - } else { - section = wxString::Format(wxT("%.4f %.4f"), MM(xpos), MM(ypos)); - } - line = module[idx]; - SetSection(line, wxT("at"), section); - module[idx] = line; - Matches++; - } - } - } - pinnr = 0; - } - } - return Matches; + int Matches = 0; + unsigned Start = 0; + long pinnr = 0; + bool inpad = false; + wxASSERT(sequence >= 1); + long range = (lastpin - firstpin) / sequence; + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + wxString keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("$PAD")) == 0) { + inpad = true; + Start = idx; /* save the position where this pad starts, because + on a match, it must be reparsed */ + } else if (keyword.CmpNoCase(wxT("$EndPAD")) == 0) { + wxASSERT(Start > 0); + wxASSERT(inpad); + bool matchpin = (pinnr >= firstpin && pinnr <= lastpin); + if (matchpin && sequence > 1) + matchpin = matchpin && ((pinnr - firstpin) % sequence) == 0; + if (matchpin) { + /* this pad matches, go through it again, to adjust it */ + for (unsigned i = Start; i < module.Count(); i++) { + wxString line = module[i]; + wxString keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("$EndPAD")) == 0) + break; + if (keyword.CmpNoCase(wxT("Po")) == 0) { + double xpos = GetTokenDim(&line, true); + double ypos = GetTokenDim(&line, true); + if (Equal(xpos, xmatch, 0.02)) { + ypos = pitch * ((pinnr - firstpin) / sequence - range / 2.0); + module[i] = wxString::Format(wxT("%s %.4f %.4f"), keyword.c_str(), MM(xpos), MM(ypos)); + Matches++; + } + } + } + } + inpad = false; + pinnr = 0; + Start = 0; + } else if (keyword.CmpNoCase(wxT("Sh")) == 0 && inpad) { + wxString field = GetToken(&line); + field.ToLong(&pinnr); + } else if (keyword.CmpNoCase(wxT("(pad")) == 0) { + /* first check the pin number */ + wxString field = GetToken(&line); + field.ToLong(&pinnr); + bool matchpin = (pinnr >= firstpin && pinnr <= lastpin); + if (matchpin && sequence > 1) + matchpin = matchpin && ((pinnr - firstpin) % sequence) == 0; + if (matchpin) { + /* this pad matches, adjust it */ + wxString section = GetSection(line, wxT("at")); + if (section.length() > 0) { + double xpos = GetTokenDim(§ion, true); + double ypos = GetTokenDim(§ion, true); + if (Equal(xpos, xmatch, 0.02)) { + ypos = pitch * ((pinnr - firstpin) / sequence - range / 2.0); + if (section.length() > 0) { + double rot = GetTokenDouble(§ion); + section = wxString::Format(wxT("%.4f %.4f %.1f"), MM(xpos), MM(ypos), rot); + } else { + section = wxString::Format(wxT("%.4f %.4f"), MM(xpos), MM(ypos)); + } + line = module[idx]; + SetSection(line, wxT("at"), section); + module[idx] = line; + Matches++; + } + } + } + pinnr = 0; + } + } + return Matches; } /** AdjustPitchGrid() changes the pitch of all pins in a grid. - * \param module The footprint data. - * \param curpitch The current pitch. - * \param newpitch The new pitch. + * \param module The footprint data. + * \param curpitch The current pitch. + * \param newpitch The new pitch. */ int AdjustPitchGrid(wxArrayString& module, double curpitch, double newpitch) { - int Matches = 0; - bool inpad = false; - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - wxString keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("$PAD")) == 0) { - inpad = true; - } else if (keyword.CmpNoCase(wxT("$EndPAD")) == 0) { - wxASSERT(inpad); - inpad = false; - } else if (keyword.CmpNoCase(wxT("Po")) == 0 && inpad) { - double xpos = GetTokenDim(&line, true); - double ypos = GetTokenDim(&line, true); - /* scale the coordinates with the factor between the current and new pitch */ - xpos *= newpitch / curpitch; - ypos *= newpitch / curpitch; - module[idx] = wxString::Format(wxT("%s %.4f %.4f"), keyword.c_str(), MM(xpos), MM(ypos)); - Matches++; - } else if (keyword.CmpNoCase(wxT("(pad")) == 0) { - wxString section = GetSection(line, wxT("at")); - if (section.length() > 0) { - double xpos = GetTokenDim(§ion, true); - double ypos = GetTokenDim(§ion, true); - /* scale the coordinates with the factor between the current and new pitch */ - xpos *= newpitch / curpitch; - ypos *= newpitch / curpitch; - line = module[idx]; - SetSection(line, wxT("at"), section); - module[idx] = line; - Matches++; - } - - } - } - return Matches; + int Matches = 0; + bool inpad = false; + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + wxString keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("$PAD")) == 0) { + inpad = true; + } else if (keyword.CmpNoCase(wxT("$EndPAD")) == 0) { + wxASSERT(inpad); + inpad = false; + } else if (keyword.CmpNoCase(wxT("Po")) == 0 && inpad) { + double xpos = GetTokenDim(&line, true); + double ypos = GetTokenDim(&line, true); + /* scale the coordinates with the factor between the current and new pitch */ + xpos *= newpitch / curpitch; + ypos *= newpitch / curpitch; + module[idx] = wxString::Format(wxT("%s %.4f %.4f"), keyword.c_str(), MM(xpos), MM(ypos)); + Matches++; + } else if (keyword.CmpNoCase(wxT("(pad")) == 0) { + wxString section = GetSection(line, wxT("at")); + if (section.length() > 0) { + double xpos = GetTokenDim(§ion, true); + double ypos = GetTokenDim(§ion, true); + /* scale the coordinates with the factor between the current and new pitch */ + xpos *= newpitch / curpitch; + ypos *= newpitch / curpitch; + line = module[idx]; + SetSection(line, wxT("at"), section); + module[idx] = line; + Matches++; + } + + } + } + return Matches; } int MovePadHor(wxArrayString& module, double from_x, double to_x) { - int Matches = 0; - bool inpad = false; - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - wxString keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("$PAD")) == 0) { - inpad = true; - } else if (keyword.CmpNoCase(wxT("$EndPAD")) == 0) { - inpad = false; - } else if (keyword.CmpNoCase(wxT("Po")) == 0 && inpad) { - double xpos = GetTokenDim(&line, true); - double ypos = GetTokenDim(&line, true); - if (Equal(xpos, from_x, 0.02)) { - module[idx] = wxString::Format(wxT("%s %.4f %.4f"), keyword.c_str(), MM(to_x), MM(ypos)); - Matches++; - } - } else if (keyword.CmpNoCase(wxT("(pad")) == 0) { - wxString section = GetSection(line, wxT("at")); - if (section.length() > 0) { - double xpos = GetTokenDim(§ion, true); - double ypos = GetTokenDim(§ion, true); - if (Equal(xpos, from_x, 0.02)) { - if (section.length() > 0) { - double rot = GetTokenDouble(§ion); - section = wxString::Format(wxT("%.4f %.4f %.1f"), MM(to_x), MM(ypos), rot); - } else { - section = wxString::Format(wxT("%.4f %.4f"), MM(to_x), MM(ypos)); - } - line = module[idx]; - SetSection(line, wxT("at"), section); - module[idx] = line; - Matches++; - } - } - } - } - return Matches; + int Matches = 0; + bool inpad = false; + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + wxString keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("$PAD")) == 0) { + inpad = true; + } else if (keyword.CmpNoCase(wxT("$EndPAD")) == 0) { + inpad = false; + } else if (keyword.CmpNoCase(wxT("Po")) == 0 && inpad) { + double xpos = GetTokenDim(&line, true); + double ypos = GetTokenDim(&line, true); + if (Equal(xpos, from_x, 0.02)) { + module[idx] = wxString::Format(wxT("%s %.4f %.4f"), keyword.c_str(), MM(to_x), MM(ypos)); + Matches++; + } + } else if (keyword.CmpNoCase(wxT("(pad")) == 0) { + wxString section = GetSection(line, wxT("at")); + if (section.length() > 0) { + double xpos = GetTokenDim(§ion, true); + double ypos = GetTokenDim(§ion, true); + if (Equal(xpos, from_x, 0.02)) { + if (section.length() > 0) { + double rot = GetTokenDouble(§ion); + section = wxString::Format(wxT("%.4f %.4f %.1f"), MM(to_x), MM(ypos), rot); + } else { + section = wxString::Format(wxT("%.4f %.4f"), MM(to_x), MM(ypos)); + } + line = module[idx]; + SetSection(line, wxT("at"), section); + module[idx] = line; + Matches++; + } + } + } + } + return Matches; } int MovePadVer(wxArrayString& module, double from_y, double to_y) { - int Matches = 0; - bool inpad = false; - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - wxString keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("$PAD")) == 0) { - inpad = true; - } else if (keyword.CmpNoCase(wxT("$EndPAD")) == 0) { - inpad = false; - } else if (keyword.CmpNoCase(wxT("Po")) == 0 && inpad) { - double xpos = GetTokenDim(&line, true); - double ypos = GetTokenDim(&line, true); - if (Equal(ypos, from_y, 0.02)) { - module[idx] = wxString::Format(wxT("%s %.4f %.4f"), keyword.c_str(), MM(xpos), MM(to_y)); - Matches++; - } - } else if (keyword.CmpNoCase(wxT("(pad")) == 0) { - wxString section = GetSection(line, wxT("at")); - if (section.length() > 0) { - double xpos = GetTokenDim(§ion, true); - double ypos = GetTokenDim(§ion, true); - if (Equal(ypos, from_y, 0.02)) { - if (section.length() > 0) { - double rot = GetTokenDouble(§ion); - section = wxString::Format(wxT("%.4f %.4f %.1f"), MM(xpos), MM(to_y), rot); - } else { - section = wxString::Format(wxT("%.4f %.4f"), MM(xpos), MM(to_y)); - } - line = module[idx]; - SetSection(line, wxT("at"), section); - module[idx] = line; - Matches++; - } - } - } - } - return Matches; + int Matches = 0; + bool inpad = false; + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + wxString keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("$PAD")) == 0) { + inpad = true; + } else if (keyword.CmpNoCase(wxT("$EndPAD")) == 0) { + inpad = false; + } else if (keyword.CmpNoCase(wxT("Po")) == 0 && inpad) { + double xpos = GetTokenDim(&line, true); + double ypos = GetTokenDim(&line, true); + if (Equal(ypos, from_y, 0.02)) { + module[idx] = wxString::Format(wxT("%s %.4f %.4f"), keyword.c_str(), MM(xpos), MM(to_y)); + Matches++; + } + } else if (keyword.CmpNoCase(wxT("(pad")) == 0) { + wxString section = GetSection(line, wxT("at")); + if (section.length() > 0) { + double xpos = GetTokenDim(§ion, true); + double ypos = GetTokenDim(§ion, true); + if (Equal(ypos, from_y, 0.02)) { + if (section.length() > 0) { + double rot = GetTokenDouble(§ion); + section = wxString::Format(wxT("%.4f %.4f %.1f"), MM(xpos), MM(to_y), rot); + } else { + section = wxString::Format(wxT("%.4f %.4f"), MM(xpos), MM(to_y)); + } + line = module[idx]; + SetSection(line, wxT("at"), section); + module[idx] = line; + Matches++; + } + } + } + } + return Matches; } -/** LibraryType() returns one of VER_MIL, VER_MM or VER_S_EXPR. - * For footprint libraries. +/** LibraryType() returns one of VER_MIL, VER_MM or VER_S_EXPR. + * For footprint libraries. */ int LibraryType(const wxString& filename) { - if (filename.CmpNoCase(LIB_REPOS) == 0) - return VER_MM; //??? this would presumably be modified to s-expression in a future version - - /* check for s-expression first (i.e. check whether "filename" is a - directory name) */ - if (wxFileName::DirExists(filename) || filename.Right(10).Cmp(wxT(".kicad_mod")) == 0) - return VER_S_EXPR; - - wxTextFile file; - if (!file.Open(filename)) - return VER_INVALID; - - wxString line = file.GetLine(0); - line = line.Left(19); - if (line.CmpNoCase(wxT("PCBNEW-LibModule-V1")) != 0) { - file.Close(); - return VER_INVALID; - } - - /* browse through the file until the first "command" (which should be the index) */ - int result = VER_MIL; - for (long idx = 1; idx < (long)file.GetLineCount(); idx++) { - line = file.GetLine(idx); - if (line[0] == wxT('$')) - break; - if (line.CmpNoCase(wxT("Units mm")) == 0) - result = VER_MM; - } - file.Close(); - - return result; + if (filename.CmpNoCase(LIB_REPOS) == 0) + return VER_MM; //??? this would presumably be modified to s-expression in a future version + + /* check for s-expression first (i.e. check whether "filename" is a + directory name) */ + if (wxFileName::DirExists(filename) || filename.Right(10).Cmp(wxT(".kicad_mod")) == 0) + return VER_S_EXPR; + + wxTextFile file; + if (!file.Open(filename)) + return VER_INVALID; + + wxString line = file.GetLine(0); + line = line.Left(19); + if (line.CmpNoCase(wxT("PCBNEW-LibModule-V1")) != 0) { + file.Close(); + return VER_INVALID; + } + + /* browse through the file until the first "command" (which should be the index) */ + int result = VER_MIL; + for (long idx = 1; idx < (long)file.GetLineCount(); idx++) { + line = file.GetLine(idx); + if (line[0] == wxT('$')) + break; + if (line.CmpNoCase(wxT("Units mm")) == 0) + result = VER_MM; + } + file.Close(); + + return result; } /** ExistFootprint() returns whether a footprint with the given name exists in * the library. - * \param filename The name of the library file (a directory in the case of - * s-expression library) - * \param name The name of the footprint - * \param author The name of the author, only used for the repository + * \param filename The name of the library file (a directory in the case of + * s-expression library) + * \param name The name of the footprint + * \param author The name of the author, only used for the repository */ bool ExistFootprint(const wxString& filename, const wxString& name, const wxString& author) { - if (filename.CmpNoCase(LIB_REPOS) == 0) { - #if defined NO_CURL - return false; - #else - wxString msg = curlGet(name, author, wxT("footprints"), 0); - return msg.length() == 0; - #endif - } else { - if (wxFileName::DirExists(filename)) { - wxFileName fname(filename, name + wxT(".kicad_mod")); - return fname.FileExists(); + if (filename.CmpNoCase(LIB_REPOS) == 0) { + #if defined NO_CURL + return false; + #else + wxString msg = curlGet(name, author, wxT("footprints"), 0); + return msg.length() == 0; + #endif + } else { + if (wxFileName::DirExists(filename)) { + wxFileName fname(filename, name + wxT(".kicad_mod")); + return fname.FileExists(); } else if (wxFileName::FileExists(filename) && filename.Right(10).CmpNoCase(".kicad_mod") == 0) { int pos = filename.Find(wxT(DIRSEP_CHAR), true); pos = (pos < 0) ? 0 : pos + 1; wxString modname = filename.Mid(pos); modname = modname.Left(modname.Length() - 10); return modname.CmpNoCase(name) == 0; - } else { - wxTextFile file; - if (!file.Open(filename)) - return false; - - /* verify the header */ - wxString line = file.GetLine(0); - line = line.Left(19); - if (line.CmpNoCase(wxT("PCBNEW-LibModule-V1")) != 0) { - file.Close(); - return false; - } - - long idx = 1; - /* find the index */ - while (idx < (long)file.GetLineCount()) { - line = file.GetLine(idx); - idx++; - if (line.CmpNoCase(wxT("$INDEX")) == 0) - break; - } - /* find the module in the index */ - int result = -1; - while (idx < (long)file.GetLineCount() && result < 0) { - line = file.GetLine(idx); - if (line.CmpNoCase(name) == 0) - result = 1; /* match found */ - else if (line[0] == wxT('$')) - result = 0; /* end-of-index reached, no match */ - idx++; - } - file.Close(); - return (result == 1); - } - } + } else { + wxTextFile file; + if (!file.Open(filename)) + return false; + + /* verify the header */ + wxString line = file.GetLine(0); + line = line.Left(19); + if (line.CmpNoCase(wxT("PCBNEW-LibModule-V1")) != 0) { + file.Close(); + return false; + } + + long idx = 1; + /* find the index */ + while (idx < (long)file.GetLineCount()) { + line = file.GetLine(idx); + idx++; + if (line.CmpNoCase(wxT("$INDEX")) == 0) + break; + } + /* find the module in the index */ + int result = -1; + while (idx < (long)file.GetLineCount() && result < 0) { + line = file.GetLine(idx); + if (line.CmpNoCase(name) == 0) + result = 1; /* match found */ + else if (line[0] == wxT('$')) + result = 0; /* end-of-index reached, no match */ + idx++; + } + file.Close(); + return (result == 1); + } + } } /** InsertFootprint() adds a footprint to a library. - * \param filename The target library name; for s-expressions, this is a + * \param filename The target library name; for s-expressions, this is a * directory name. - * \param name The name of the footprint; this becomes a filename for + * \param name The name of the footprint; this becomes a filename for * an s-expression library. - * \param module The complete contents of the footprint; this may be in - * either legacy or s-expression format (and it must - * already match the format of the library) - * \param unit_mm Whether the source in \c module uses mm as a unit (as - * opposed to 0.1 mil). + * \param module The complete contents of the footprint; this may be in + * either legacy or s-expression format (and it must + * already match the format of the library) + * \param unit_mm Whether the source in \c module uses mm as a unit (as + * opposed to 0.1 mil). */ bool InsertFootprint(const wxString& filename, const wxString& name, const wxArrayString& module, bool unit_mm) { - int type = LibraryType(filename); - if (type == VER_INVALID) - return false; - - if (filename.CmpNoCase(LIB_REPOS) == 0) { - #if defined NO_CURL - return false; - #else - /* make a copy of the module, so that it can be translated */ - wxArrayString mod = module; - TranslateUnits(mod, unit_mm, true); - wxString msg = curlPut(name, wxT("footprints"), mod); - return msg.length() == 0; - #endif - } else { - wxTextFile file; - if (type == VER_S_EXPR) { - wxFileName fname(filename, name + wxT(".kicad_mod")); + int type = LibraryType(filename); + if (type == VER_INVALID) + return false; + + if (filename.CmpNoCase(LIB_REPOS) == 0) { + #if defined NO_CURL + return false; + #else + /* make a copy of the module, so that it can be translated */ + wxArrayString mod = module; + TranslateUnits(mod, unit_mm, true); + wxString msg = curlPut(name, wxT("footprints"), mod); + return msg.length() == 0; + #endif + } else { + wxTextFile file; + if (type == VER_S_EXPR) { + wxFileName fname(filename, name + wxT(".kicad_mod")); if (filename.Right(10).CmpNoCase(wxT(".kicad_mod")) == 0) fname = filename; - if (wxFileExists(fname.GetFullPath())) - wxRemoveFile(fname.GetFullPath()); - if (!file.Create(fname.GetFullPath())) - return false; - /* insert all lines of the module, indent all except the first and the last */ - bool inheader = true; - wxString line; - for (unsigned idx = 0; idx < module.Count(); idx++) { - if (inheader || idx == module.Count() - 1) - line = module[idx]; - else - line = wxT(" ") + module[idx]; - if (line[0] != wxT('#')) - inheader = false; - file.InsertLine(line, idx); - } - } else { - /* check whether "filename" uses 1/10 mil or mm dimensions */ - bool tgt_mm = (type == VER_MM); - - if (!file.Open(filename)) - return false; - /* no need to verify the header, function LibraryType() did that already */ - - /* insert name in the index */ - wxString line; - long idx = 1; - /* find the start of the index */ - while (idx < (long)file.GetLineCount()) { - line = file.GetLine(idx); - idx++; - if (line.CmpNoCase(wxT("$INDEX")) == 0) - break; - } - /* find the position to store the name */ - while (idx < (long)file.GetLineCount()) { - line = file.GetLine(idx); - int cmp = line.CmpNoCase(name); - if (line[0] == wxT('$') || cmp > 0) { - file.InsertLine(name, idx); - break; - } else if (cmp == 0) { - return false; /* symbol already present, insertion fails */ - } - idx++; - } - /* skip to the end of the index */ - while (idx < (long)file.GetLineCount()) { - line = file.GetLine(idx); - idx++; - if (line.CmpNoCase(wxT("$EndINDEX")) == 0) - break; - } - - /* make a copy of the module, so that it can be translated */ - wxArrayString mod = module; - TranslateUnits(mod, unit_mm, tgt_mm); - - /* now find the insertion position for the module itself (this probably - does not have to stay sorted, but we do it anyway) */ - wxString keyword; - while (idx < (long)file.GetLineCount()) { - line = file.GetLine(idx); - if (line[0] == '$' && line.Left(7).CmpNoCase(wxT("$MODULE")) == 0) { - GetToken(&line); - keyword = GetToken(&line); - if (keyword.CmpNoCase(name) > 0) - break; - } else if (line.CmpNoCase(wxT("$EndLIBRARY")) == 0) { - break; - } - idx++; - } - /* insert all lines of the module */ - for (long l = 0; l < (long)mod.Count(); l++) { - file.InsertLine(mod[l], idx); - idx++; - } - } - - file.Write(); - file.Close(); - return true; - } + if (wxFileExists(fname.GetFullPath())) + wxRemoveFile(fname.GetFullPath()); + if (!file.Create(fname.GetFullPath())) + return false; + /* insert all lines of the module, indent all except the first and the last */ + bool inheader = true; + wxString line; + for (unsigned idx = 0; idx < module.Count(); idx++) { + if (inheader || idx == module.Count() - 1) + line = module[idx]; + else + line = wxT(" ") + module[idx]; + if (line[0] != wxT('#')) + inheader = false; + file.InsertLine(line, idx); + } + } else { + /* check whether "filename" uses 1/10 mil or mm dimensions */ + bool tgt_mm = (type == VER_MM); + + if (!file.Open(filename)) + return false; + /* no need to verify the header, function LibraryType() did that already */ + + /* insert name in the index */ + wxString line; + long idx = 1; + /* find the start of the index */ + while (idx < (long)file.GetLineCount()) { + line = file.GetLine(idx); + idx++; + if (line.CmpNoCase(wxT("$INDEX")) == 0) + break; + } + /* find the position to store the name */ + while (idx < (long)file.GetLineCount()) { + line = file.GetLine(idx); + int cmp = line.CmpNoCase(name); + if (line[0] == wxT('$') || cmp > 0) { + file.InsertLine(name, idx); + break; + } else if (cmp == 0) { + return false; /* symbol already present, insertion fails */ + } + idx++; + } + /* skip to the end of the index */ + while (idx < (long)file.GetLineCount()) { + line = file.GetLine(idx); + idx++; + if (line.CmpNoCase(wxT("$EndINDEX")) == 0) + break; + } + + /* make a copy of the module, so that it can be translated */ + wxArrayString mod = module; + TranslateUnits(mod, unit_mm, tgt_mm); + + /* now find the insertion position for the module itself (this probably + does not have to stay sorted, but we do it anyway) */ + wxString keyword; + while (idx < (long)file.GetLineCount()) { + line = file.GetLine(idx); + if (line[0] == '$' && line.Left(7).CmpNoCase(wxT("$MODULE")) == 0) { + GetToken(&line); + keyword = GetToken(&line); + if (keyword.CmpNoCase(name) > 0) + break; + } else if (line.CmpNoCase(wxT("$EndLIBRARY")) == 0) { + break; + } + idx++; + } + /* insert all lines of the module */ + for (long l = 0; l < (long)mod.Count(); l++) { + file.InsertLine(mod[l], idx); + idx++; + } + } + + file.Write(); + file.Close(); + return true; + } } /* For footprints */ bool RemoveFootprint(const wxString& filename, const wxString& name) { - if (filename.CmpNoCase(LIB_REPOS) == 0) { - #if defined NO_CURL - return false; - #else - wxString msg = curlDelete(name, wxT("footprints")); - return msg.length() == 0; - #endif - } else if (wxFileName::DirExists(filename)) { - wxFileName fname(filename, name + wxT(".kicad_mod")); - return wxFileExists(fname.GetFullPath()) && wxRemoveFile(fname.GetFullPath()); + if (filename.CmpNoCase(LIB_REPOS) == 0) { + #if defined NO_CURL + return false; + #else + wxString msg = curlDelete(name, wxT("footprints")); + return msg.length() == 0; + #endif + } else if (wxFileName::DirExists(filename)) { + wxFileName fname(filename, name + wxT(".kicad_mod")); + return wxFileExists(fname.GetFullPath()) && wxRemoveFile(fname.GetFullPath()); } else if (wxFileName::FileExists(filename) && filename.Right(10).CmpNoCase(".kicad_mod") == 0) { int pos = filename.Find(wxT(DIRSEP_CHAR), true); pos = (pos < 0) ? 0 : pos + 1; @@ -2208,846 +2208,846 @@ bool RemoveFootprint(const wxString& filename, const wxString& name) modname = modname.Left(modname.Length() - 10); if (modname.CmpNoCase(name) != 0) return false; - return wxRemoveFile(filename); - } else { - wxTextFile file; - if (!file.Open(filename)) - return false; - - /* verify the header */ - wxString line = file.GetLine(0); - line = line.Left(19); - if (line.CmpNoCase(wxT("PCBNEW-LibModule-V1")) != 0) { - file.Close(); - return false; - } - - long idx = 1; - /* find the index */ - while (idx < (long)file.GetLineCount()) { - line = file.GetLine(idx); - idx++; - if (line.CmpNoCase(wxT("$INDEX")) == 0) - break; - } - /* find the module in the index */ - while (idx < (long)file.GetLineCount()) { - line = file.GetLine(idx); - if (line.CmpNoCase(name) == 0) { - file.RemoveLine(idx); - break; - } else if (line[0] == wxT('$')) { - file.Close(); - return false; /* module not found in the index, skip other operations */ - } - idx++; - } - /* skip to the end of the index */ - while (idx < (long)file.GetLineCount()) { - line = file.GetLine(idx); - idx++; - if (line.CmpNoCase(wxT("$EndINDEX")) == 0) - break; - } - /* now find the module itself */ - wxString keyword; - while (idx < (long)file.GetLineCount()) { - line = file.GetLine(idx); - if (line[0] == '$' && line.Left(7).CmpNoCase(wxT("$MODULE")) == 0) { - keyword = GetToken(&line); - if (line.CmpNoCase(name) == 0) - break; - } - idx++; - } - /* delete all lines of the module */ - while (idx < (long)file.GetLineCount()) { - line = file.GetLine(idx); - file.RemoveLine(idx); - if (line.Left(10).CmpNoCase(wxT("$EndMODULE")) == 0) - break; - } - - file.Write(); - file.Close(); - } - return true; + return wxRemoveFile(filename); + } else { + wxTextFile file; + if (!file.Open(filename)) + return false; + + /* verify the header */ + wxString line = file.GetLine(0); + line = line.Left(19); + if (line.CmpNoCase(wxT("PCBNEW-LibModule-V1")) != 0) { + file.Close(); + return false; + } + + long idx = 1; + /* find the index */ + while (idx < (long)file.GetLineCount()) { + line = file.GetLine(idx); + idx++; + if (line.CmpNoCase(wxT("$INDEX")) == 0) + break; + } + /* find the module in the index */ + while (idx < (long)file.GetLineCount()) { + line = file.GetLine(idx); + if (line.CmpNoCase(name) == 0) { + file.RemoveLine(idx); + break; + } else if (line[0] == wxT('$')) { + file.Close(); + return false; /* module not found in the index, skip other operations */ + } + idx++; + } + /* skip to the end of the index */ + while (idx < (long)file.GetLineCount()) { + line = file.GetLine(idx); + idx++; + if (line.CmpNoCase(wxT("$EndINDEX")) == 0) + break; + } + /* now find the module itself */ + wxString keyword; + while (idx < (long)file.GetLineCount()) { + line = file.GetLine(idx); + if (line[0] == '$' && line.Left(7).CmpNoCase(wxT("$MODULE")) == 0) { + keyword = GetToken(&line); + if (line.CmpNoCase(name) == 0) + break; + } + idx++; + } + /* delete all lines of the module */ + while (idx < (long)file.GetLineCount()) { + line = file.GetLine(idx); + file.RemoveLine(idx); + if (line.Left(10).CmpNoCase(wxT("$EndMODULE")) == 0) + break; + } + + file.Write(); + file.Close(); + } + return true; } /* For footprints */ bool RenameFootprint(wxArrayString* module, const wxString& oldname, const wxString& newname) { - for (int idx = 0; idx < (int)module->Count(); idx++) { - wxString line = (*module)[idx]; - wxString keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("$MODULE")) == 0 - || keyword.CmpNoCase(wxT("$EndMODULE")) == 0 - || keyword.CmpNoCase(wxT("Li")) == 0) - { - (*module)[idx] = keyword + wxT(" ") + newname; - } else if (keyword.CmpNoCase(wxT("T0")) == 0 - || keyword.Cmp(wxT("Na")) == 0 - || keyword.Cmp(wxT("(module")) == 0 - || keyword.Cmp(wxT("(model")) == 0 - || keyword.Cmp(wxT("(fp_text")) == 0 - ) - { - (*module)[idx].Replace(oldname, newname); - } - } - return true; + for (int idx = 0; idx < (int)module->Count(); idx++) { + wxString line = (*module)[idx]; + wxString keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("$MODULE")) == 0 + || keyword.CmpNoCase(wxT("$EndMODULE")) == 0 + || keyword.CmpNoCase(wxT("Li")) == 0) + { + (*module)[idx] = keyword + wxT(" ") + newname; + } else if (keyword.CmpNoCase(wxT("T0")) == 0 + || keyword.Cmp(wxT("Na")) == 0 + || keyword.Cmp(wxT("(module")) == 0 + || keyword.Cmp(wxT("(model")) == 0 + || keyword.Cmp(wxT("(fp_text")) == 0 + ) + { + (*module)[idx].Replace(oldname, newname); + } + } + return true; } /* For footprints */ bool RenameFootprint(const wxString& filename, const wxString& oldname, const wxString& newname) { - if (filename.CmpNoCase(LIB_REPOS) == 0) { - #if defined NO_CURL - return false; - #else - wxArrayString module; - wxString msg = curlGet(oldname, wxEmptyString, wxT("footprints"), &module); - if (msg.length() > 0) - return false; - RenameFootprint(&module, oldname, newname); - msg = curlPut(newname, wxT("footprints"), module); - if (msg.length() > 0) - return false; - msg = curlDelete(oldname, wxT("footprints")); - return msg.length() == 0; - #endif - } else if (wxFileName::DirExists(filename)) { - wxFileName old_fname(filename, oldname + wxT(".kicad_mod")); - wxFileName new_fname(filename, newname + wxT(".kicad_mod")); - if (!wxRenameFile(old_fname.GetFullPath(), new_fname.GetFullPath(), true)) - return false; - wxTextFile file; - if (!file.Open(new_fname.GetFullPath())) - return false; - wxArrayString module; - /* find the index */ - for (unsigned idx = 0; idx < file.GetLineCount(); idx++) { - wxString line = file.GetLine(idx); - module.Add(line); - } - RenameFootprint(&module, oldname, newname); - file.Clear(); - for (unsigned idx = 0; idx < module.Count(); idx++) - file.AddLine(module[idx]); - file.Write(); - file.Close(); - } else { - wxTextFile file; - if (!file.Open(filename)) - return false; - - /* verify the header */ - wxString line = file.GetLine(0); - line = line.Left(19); - if (line.CmpNoCase(wxT("PCBNEW-LibModule-V1")) != 0) { - file.Close(); - return false; - } - - long idx = 1; - /* find the index */ - while (idx < (long)file.GetLineCount()) { - line = file.GetLine(idx); - idx++; - if (line.CmpNoCase(wxT("$INDEX")) == 0) - break; - } - /* find the module in the index */ - while (idx < (long)file.GetLineCount()) { - line = file.GetLine(idx); - if (line.CmpNoCase(oldname) == 0) { - file.RemoveLine(idx); - file.InsertLine(newname, idx); - break; - } else if (line[0] == wxT('$')) { - file.Close(); - return false; /* module not found in the index, skip other operations */ - } - idx++; - } - /* skip to the end of the index */ - while (idx < (long)file.GetLineCount()) { - line = file.GetLine(idx); - idx++; - if (line.CmpNoCase(wxT("$EndINDEX")) == 0) - break; - } - /* now find the module itself */ - wxString keyword; - while (idx < (long)file.GetLineCount()) { - line = file.GetLine(idx); - if (line[0] == '$' && line.Left(7).CmpNoCase(wxT("$MODULE")) == 0) { - keyword = GetToken(&line); - if (line.CmpNoCase(oldname) == 0) - break; - } - idx++; - } - /* go through the module, translate a few strings */ - while (idx < (long)file.GetLineCount()) { - line = file.GetLine(idx); - keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("$MODULE")) == 0 - || keyword.CmpNoCase(wxT("$EndMODULE")) == 0 - || keyword.CmpNoCase(wxT("Li")) == 0) - { - file.RemoveLine(idx); - line = keyword + wxT(" ") + newname; - file.InsertLine(line, idx); - } else if (keyword.CmpNoCase(wxT("T0")) == 0 || keyword.Cmp(wxT("Na")) == 0) { - line.Replace(oldname, newname); - file.RemoveLine(idx); - line = keyword + wxT(" ") + line; - file.InsertLine(line, idx); - } - if (keyword.CmpNoCase(wxT("$EndMODULE")) == 0) - break; - idx++; - } - - file.Write(); - file.Close(); - } - return true; + if (filename.CmpNoCase(LIB_REPOS) == 0) { + #if defined NO_CURL + return false; + #else + wxArrayString module; + wxString msg = curlGet(oldname, wxEmptyString, wxT("footprints"), &module); + if (msg.length() > 0) + return false; + RenameFootprint(&module, oldname, newname); + msg = curlPut(newname, wxT("footprints"), module); + if (msg.length() > 0) + return false; + msg = curlDelete(oldname, wxT("footprints")); + return msg.length() == 0; + #endif + } else if (wxFileName::DirExists(filename)) { + wxFileName old_fname(filename, oldname + wxT(".kicad_mod")); + wxFileName new_fname(filename, newname + wxT(".kicad_mod")); + if (!wxRenameFile(old_fname.GetFullPath(), new_fname.GetFullPath(), true)) + return false; + wxTextFile file; + if (!file.Open(new_fname.GetFullPath())) + return false; + wxArrayString module; + /* find the index */ + for (unsigned idx = 0; idx < file.GetLineCount(); idx++) { + wxString line = file.GetLine(idx); + module.Add(line); + } + RenameFootprint(&module, oldname, newname); + file.Clear(); + for (unsigned idx = 0; idx < module.Count(); idx++) + file.AddLine(module[idx]); + file.Write(); + file.Close(); + } else { + wxTextFile file; + if (!file.Open(filename)) + return false; + + /* verify the header */ + wxString line = file.GetLine(0); + line = line.Left(19); + if (line.CmpNoCase(wxT("PCBNEW-LibModule-V1")) != 0) { + file.Close(); + return false; + } + + long idx = 1; + /* find the index */ + while (idx < (long)file.GetLineCount()) { + line = file.GetLine(idx); + idx++; + if (line.CmpNoCase(wxT("$INDEX")) == 0) + break; + } + /* find the module in the index */ + while (idx < (long)file.GetLineCount()) { + line = file.GetLine(idx); + if (line.CmpNoCase(oldname) == 0) { + file.RemoveLine(idx); + file.InsertLine(newname, idx); + break; + } else if (line[0] == wxT('$')) { + file.Close(); + return false; /* module not found in the index, skip other operations */ + } + idx++; + } + /* skip to the end of the index */ + while (idx < (long)file.GetLineCount()) { + line = file.GetLine(idx); + idx++; + if (line.CmpNoCase(wxT("$EndINDEX")) == 0) + break; + } + /* now find the module itself */ + wxString keyword; + while (idx < (long)file.GetLineCount()) { + line = file.GetLine(idx); + if (line[0] == '$' && line.Left(7).CmpNoCase(wxT("$MODULE")) == 0) { + keyword = GetToken(&line); + if (line.CmpNoCase(oldname) == 0) + break; + } + idx++; + } + /* go through the module, translate a few strings */ + while (idx < (long)file.GetLineCount()) { + line = file.GetLine(idx); + keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("$MODULE")) == 0 + || keyword.CmpNoCase(wxT("$EndMODULE")) == 0 + || keyword.CmpNoCase(wxT("Li")) == 0) + { + file.RemoveLine(idx); + line = keyword + wxT(" ") + newname; + file.InsertLine(line, idx); + } else if (keyword.CmpNoCase(wxT("T0")) == 0 || keyword.Cmp(wxT("Na")) == 0) { + line.Replace(oldname, newname); + file.RemoveLine(idx); + line = keyword + wxT(" ") + line; + file.InsertLine(line, idx); + } + if (keyword.CmpNoCase(wxT("$EndMODULE")) == 0) + break; + idx++; + } + + file.Write(); + file.Close(); + } + return true; } /** LoadFootprint() loads a footprint. - * \param filename The name of the library (which is a directory for - * s-expression libraries), or the repository string - * \param name The footprint name - * \param author The name of the author of the footprint; only used for the - * repository - * \param striplink If true, the link with the template is stripped from the - * module - * \param module The array that will hold the footprint data on output - * \param version The library file format version + * \param filename The name of the library (which is a directory for + * s-expression libraries), or the repository string + * \param name The footprint name + * \param author The name of the author of the footprint; only used for the + * repository + * \param striplink If true, the link with the template is stripped from the + * module + * \param module The array that will hold the footprint data on output + * \param version The library file format version */ bool LoadFootprint(const wxString& filename, const wxString& name, const wxString& author, - bool striplink, wxArrayString* module, int* version) + bool striplink, wxArrayString* module, int* version) { - wxASSERT(module != NULL); - module->Clear(); - wxASSERT(version != NULL); - *version = VER_INVALID; - - bool result = false; - - if (filename.CmpNoCase(LIB_REPOS) == 0) { - #if defined NO_CURL - return false; - #else - wxString msg = curlGet(name, author, wxT("footprints"), module); - if (msg.length() == 0) - *version = VER_MM; //??? this will presumably change to VER_S_EXPR in a future version - result = (msg.length() == 0 && module->Count() > 0); - #endif - } else { - wxTextFile file; - /* check whether this is an s-expression library */ - if (wxFileName::DirExists(filename) || filename.Right(10).Cmp(wxT(".kicad_mod")) == 0) { + wxASSERT(module != NULL); + module->Clear(); + wxASSERT(version != NULL); + *version = VER_INVALID; + + bool result = false; + + if (filename.CmpNoCase(LIB_REPOS) == 0) { + #if defined NO_CURL + return false; + #else + wxString msg = curlGet(name, author, wxT("footprints"), module); + if (msg.length() == 0) + *version = VER_MM; //??? this will presumably change to VER_S_EXPR in a future version + result = (msg.length() == 0 && module->Count() > 0); + #endif + } else { + wxTextFile file; + /* check whether this is an s-expression library */ + if (wxFileName::DirExists(filename) || filename.Right(10).Cmp(wxT(".kicad_mod")) == 0) { wxString mod_name; if (wxFileName::DirExists(filename)) { - /* the symbol name may contain periods, and the part after the last period may then be - misdetected as an extension, if we use fname.SetExt() -> so we concatenate the - extension rather than use SetExt() */ - wxFileName fname(filename, name + wxT(".kicad_mod")); + /* the symbol name may contain periods, and the part after the last period may then be + misdetected as an extension, if we use fname.SetExt() -> so we concatenate the + extension rather than use SetExt() */ + wxFileName fname(filename, name + wxT(".kicad_mod")); mod_name = fname.GetFullPath(); } else { mod_name = filename; } - if (!file.Open(mod_name)) - return false; - *version = VER_S_EXPR; - /* s-expression is a free-format; for ease of parsing, the contents are - reformatted; the first step is to gather all data in a single (long) - string */ - wxString total = wxEmptyString; - wxString line; - for (unsigned idx = 0; idx < file.GetLineCount(); idx++) { - line = file.GetLine(idx); - line.Trim(false); /* remove leading and trailing white-space */ - line.Trim(true); - if (total.length() > 0 && line.length() > 0 && line[0] != wxT(')')) - total += wxT(" "); /* put one space between sections/keywords */ - total += line; - if (line.Find(wxT('#')) >= 0) - total += wxT(EoC); /* if a comment appears in the string, append a special "end-of-comment" token */ - } - file.Close(); - /* remove spaces after a '(' (KiCad does not generate these, so it is merely - to be extra sure) */ - total.Replace(wxT("( "), wxT("(")); - /* handle any leading comments */ - while (total[0] == wxT('#')) { - int pos = total.Find(wxT(EoC)); - wxASSERT(pos > 0); - line = total.Left(pos); - module->Add(line); - total = total.Mid(pos + 1); - } - /* reformat with only a single "indentation level" (although no indentation - is added) */ - total.Trim(true); /* trim trailing */ - total.Trim(false); /* trim leading */ - wxASSERT(total[0] == wxT('(')); - unsigned start = 1; + if (!file.Open(mod_name)) + return false; + *version = VER_S_EXPR; + /* s-expression is a free-format; for ease of parsing, the contents are + reformatted; the first step is to gather all data in a single (long) + string */ + wxString total = wxEmptyString; + wxString line; + for (unsigned idx = 0; idx < file.GetLineCount(); idx++) { + line = file.GetLine(idx); + line.Trim(false); /* remove leading and trailing white-space */ + line.Trim(true); + if (total.length() > 0 && line.length() > 0 && line[0] != wxT(')')) + total += wxT(" "); /* put one space between sections/keywords */ + total += line; + if (line.Find(wxT('#')) >= 0) + total += wxT(EoC); /* if a comment appears in the string, append a special "end-of-comment" token */ + } + file.Close(); + /* remove spaces after a '(' (KiCad does not generate these, so it is merely + to be extra sure) */ + total.Replace(wxT("( "), wxT("(")); + /* handle any leading comments */ + while (total[0] == wxT('#')) { + int pos = total.Find(wxT(EoC)); + wxASSERT(pos > 0); + line = total.Left(pos); + module->Add(line); + total = total.Mid(pos + 1); + } + /* reformat with only a single "indentation level" (although no indentation + is added) */ + total.Trim(true); /* trim trailing */ + total.Trim(false); /* trim leading */ + wxASSERT(total[0] == wxT('(')); + unsigned start = 1; bool instring = false; - while (start < total.length() && (!(total[start] == wxT('(') || total[start] == wxT(')')) || instring)) { + while (start < total.length() && (!(total[start] == wxT('(') || total[start] == wxT(')')) || instring)) { if (total[start] == wxT('"')) instring = !instring; - start++; - } - line = total.Left(start); - line.Trim(true); - module->Add(line); - total = total.Mid(start); - total.Trim(false); - while (total[0] != wxT(')')) { - wxASSERT(total[0] == wxT('(')); - int level = 0; + start++; + } + line = total.Left(start); + line.Trim(true); + module->Add(line); + total = total.Mid(start); + total.Trim(false); + while (total[0] != wxT(')')) { + wxASSERT(total[0] == wxT('(')); + int level = 0; instring = false; - for (start = 1; start < total.length() && level >= 0; start++) { + for (start = 1; start < total.length() && level >= 0; start++) { if (total[start] == wxT('"')) instring = !instring; - if (total[start] == wxT('(') && !instring) - level++; - else if (total[start] == wxT(')') && !instring) - level--; - } - line = total.Left(start); - /* remove comments (right now, we only support header comments) */ - int pos; - while ((pos = line.Find(wxT('#'))) >= 0) { - int pos2 = line.Find(wxT(EoC)); - wxASSERT(pos2 > pos); - line.Remove(pos, pos2 - pos + 1); - } - module->Add(line); - total = total.Mid(start); - total.Trim(false); /* remove the space after the closing ')' */ - } - module->Add(total); /* this is the final ')' that closes the module definition */ - result = (module->Count() > 0); - } else { - /* legacy library, open the library */ - if (!file.Open(filename)) - return false; - - /* verify the header */ - wxString line = file.GetLine(0); - line = line.Left(19); - if (line.CmpNoCase(wxT("PCBNEW-LibModule-V1")) != 0) { - file.Close(); - return false; - } - - /* search for the unit (this may be absent) */ - wxASSERT(version != NULL); - *version = VER_MIL; - unsigned idx = 1; - while (idx < file.GetLineCount()) { - line = file.GetLine(idx); - idx++; - if (line[0] == '$') - break; /* the unit must appear before the index, and before any module */ - wxString keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("Units")) == 0 && line.CmpNoCase(wxT("mm")) == 0) - *version = VER_MM; - } - - /* search the module */ - while (idx < file.GetLineCount()) { - line = file.GetLine(idx); - idx++; - if (line[0] != '$') - continue; - wxString keyword = line.Left(7); - if (keyword.CmpNoCase(wxT("$MODULE")) != 0) - continue; - line.Trim(); /* remove trailing white-space */ - wxString modname = line.Mid(8); - modname.Trim(false); /* remove leading white-space (trailing white-space was already removed) */ - if (modname.CmpNoCase(name) == 0) { - module->Add(line); /* already add the header line to the saved data */ - break; - } - } - - /* read the module */ - while (idx < file.GetLineCount()) { - line = file.GetLine(idx); - module->Add(line); - line.Trim(); - line.Trim(false); - if (line[0] == '$' && line.Left(10).CmpNoCase(wxT("$EndMODULE")) == 0) - break; - idx++; - } - - file.Close(); - result = (module->Count() > 0); - } - } - - if (result && striplink) { - for (unsigned idx = 0; idx < module->Count(); idx++) { - wxString line = (*module)[idx]; - wxString keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("AR")) == 0) - (*module)[idx] = keyword; - else if (keyword.Cmp(wxT("#template")) == 0) - (*module)[idx] = wxT("#"); - } - } - return result; + if (total[start] == wxT('(') && !instring) + level++; + else if (total[start] == wxT(')') && !instring) + level--; + } + line = total.Left(start); + /* remove comments (right now, we only support header comments) */ + int pos; + while ((pos = line.Find(wxT('#'))) >= 0) { + int pos2 = line.Find(wxT(EoC)); + wxASSERT(pos2 > pos); + line.Remove(pos, pos2 - pos + 1); + } + module->Add(line); + total = total.Mid(start); + total.Trim(false); /* remove the space after the closing ')' */ + } + module->Add(total); /* this is the final ')' that closes the module definition */ + result = (module->Count() > 0); + } else { + /* legacy library, open the library */ + if (!file.Open(filename)) + return false; + + /* verify the header */ + wxString line = file.GetLine(0); + line = line.Left(19); + if (line.CmpNoCase(wxT("PCBNEW-LibModule-V1")) != 0) { + file.Close(); + return false; + } + + /* search for the unit (this may be absent) */ + wxASSERT(version != NULL); + *version = VER_MIL; + unsigned idx = 1; + while (idx < file.GetLineCount()) { + line = file.GetLine(idx); + idx++; + if (line[0] == '$') + break; /* the unit must appear before the index, and before any module */ + wxString keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("Units")) == 0 && line.CmpNoCase(wxT("mm")) == 0) + *version = VER_MM; + } + + /* search the module */ + while (idx < file.GetLineCount()) { + line = file.GetLine(idx); + idx++; + if (line[0] != '$') + continue; + wxString keyword = line.Left(7); + if (keyword.CmpNoCase(wxT("$MODULE")) != 0) + continue; + line.Trim(); /* remove trailing white-space */ + wxString modname = line.Mid(8); + modname.Trim(false); /* remove leading white-space (trailing white-space was already removed) */ + if (modname.CmpNoCase(name) == 0) { + module->Add(line); /* already add the header line to the saved data */ + break; + } + } + + /* read the module */ + while (idx < file.GetLineCount()) { + line = file.GetLine(idx); + module->Add(line); + line.Trim(); + line.Trim(false); + if (line[0] == '$' && line.Left(10).CmpNoCase(wxT("$EndMODULE")) == 0) + break; + idx++; + } + + file.Close(); + result = (module->Count() > 0); + } + } + + if (result && striplink) { + for (unsigned idx = 0; idx < module->Count(); idx++) { + wxString line = (*module)[idx]; + wxString keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("AR")) == 0) + (*module)[idx] = keyword; + else if (keyword.Cmp(wxT("#template")) == 0) + (*module)[idx] = wxT("#"); + } + } + return result; } /* For templates (footprints & symbols) */ bool LoadTemplate(const wxString& templatename, wxArrayString* module, bool SymbolMode) { - wxASSERT(module); - module->Clear(); - - wxString ext = SymbolMode ? wxT(".st") : wxT(".mt"); - wxString path = theApp->GetTemplatePath() + wxT(DIRSEP_STR) + templatename + ext; - wxTextFile file; - if (file.Open(path)) { - wxString line; - for (unsigned idx = 0; idx < file.GetLineCount(); idx++) { - wxString segm = file.GetLine(idx); - /* strip trailing comments */ - int pos = segm.Find(wxT('#')); - if (pos >= 0) - segm = segm.Left(pos); - segm.Trim(); /* remove leading and trailing white space */ - segm.Trim(false); - line += segm; - /* check for line continuation before adding the line to the list */ - size_t len = line.length(); - if (len > 0) { - if (line[len - 1] == wxT('\\')) { - line[len - 1] = wxT(' '); - } else { - module->Add(line); - line.Clear(); - } - } - } - file.Close(); - } - return module->Count() > 0; + wxASSERT(module); + module->Clear(); + + wxString ext = SymbolMode ? wxT(".st") : wxT(".mt"); + wxString path = theApp->GetTemplatePath() + wxT(DIRSEP_STR) + templatename + ext; + wxTextFile file; + if (file.Open(path)) { + wxString line; + for (unsigned idx = 0; idx < file.GetLineCount(); idx++) { + wxString segm = file.GetLine(idx); + /* strip trailing comments */ + int pos = segm.Find(wxT('#')); + if (pos >= 0) + segm = segm.Left(pos); + segm.Trim(); /* remove leading and trailing white space */ + segm.Trim(false); + line += segm; + /* check for line continuation before adding the line to the list */ + size_t len = line.length(); + if (len > 0) { + if (line[len - 1] == wxT('\\')) { + line[len - 1] = wxT(' '); + } else { + module->Add(line); + line.Clear(); + } + } + } + file.Close(); + } + return module->Count() > 0; } /* For templates (sub-function) and for generated VRML files if a key occurs multiple times, the "sequence" parameter allows to run through them */ wxString GetFileHeaderField(const wxString& path, const wxString& key, int sequence) { - if (!wxFileExists(path)) - return wxEmptyString; - wxTextFile file; - wxString result = wxEmptyString; - if (file.Open(path)) { - wxString line; - for (unsigned idx = 0; idx < file.GetLineCount(); idx++) { - line = file.GetLine(idx); - if (line[0] != wxT('#')) - break; /* end of the header found, return an empty string */ - wxString token = GetToken(&line); - token = token.Mid(1); /* strip of '#' */ - if (token.Cmp(key) == 0) { - if (sequence-- == 0) { - line.Trim(true); - result = line; - /* test for line continuation */ - size_t len = result.length(); - while (len > 0 && result[len - 1] == wxT('\\')) { - result[len - 1] = wxT(' '); /* replace \ by space */ - if (++idx >= file.GetLineCount()) - break; /* no more lines in the file, cannot continue (this is an error in the template) */ - line = file.GetLine(idx); - if (line[0] != wxT('#')) - break; /* end of the header found (this is also an error in the template) */ - line = line.Mid(1); /* erase # */ - line.Trim(false); /* remove leading and trailing whitespace */ - line.Trim(true); - result += line; - len = result.length(); - } - result.Trim(true); - break; /* token found, no need to search further */ - } - } - } - file.Close(); - } - return result; + if (!wxFileExists(path)) + return wxEmptyString; + wxTextFile file; + wxString result = wxEmptyString; + if (file.Open(path)) { + wxString line; + for (unsigned idx = 0; idx < file.GetLineCount(); idx++) { + line = file.GetLine(idx); + if (line[0] != wxT('#')) + break; /* end of the header found, return an empty string */ + wxString token = GetToken(&line); + token = token.Mid(1); /* strip of '#' */ + if (token.Cmp(key) == 0) { + if (sequence-- == 0) { + line.Trim(true); + result = line; + /* test for line continuation */ + size_t len = result.length(); + while (len > 0 && result[len - 1] == wxT('\\')) { + result[len - 1] = wxT(' '); /* replace \ by space */ + if (++idx >= file.GetLineCount()) + break; /* no more lines in the file, cannot continue (this is an error in the template) */ + line = file.GetLine(idx); + if (line[0] != wxT('#')) + break; /* end of the header found (this is also an error in the template) */ + line = line.Mid(1); /* erase # */ + line.Trim(false); /* remove leading and trailing whitespace */ + line.Trim(true); + result += line; + len = result.length(); + } + result.Trim(true); + break; /* token found, no need to search further */ + } + } + } + file.Close(); + } + return result; } /* For templates (footprints & symbols) */ wxString GetTemplateHeaderField(const wxString& templatename, const wxString& key, bool SymbolMode, int sequence) { - wxString ext = SymbolMode ? wxT(".st") : wxT(".mt"); - wxString path = theApp->GetTemplatePath() + wxT(DIRSEP_STR) + templatename + ext; + wxString ext = SymbolMode ? wxT(".st") : wxT(".mt"); + wxString path = theApp->GetTemplatePath() + wxT(DIRSEP_STR) + templatename + ext; return GetFileHeaderField(path, key, sequence); } /* get sections for pins (currently for symbols only) */ void GetTemplateSections(const wxString& templatename, PinSection sections[], size_t max) { - wxASSERT(sections); - int idx = 0; - if (templatename.Length() > 0) { - while (idx < (int)max) { - wxString sect = GetTemplateHeaderField(templatename, wxT("section"), true, idx); - if (sect.Length() == 0) - break; - /* extract the name, the side and the criterion */ - wxString name = GetToken(§); - wxString side = GetToken(§); - double crit; - sect.ToDouble(&crit); - sections[idx].SetCriterion(name, side, crit); - idx++; - } - } - /* clear any remaining sections */ - while (idx < (int)max) { - sections[idx].Clear(); - idx++; - } + wxASSERT(sections); + int idx = 0; + if (templatename.Length() > 0) { + while (idx < (int)max) { + wxString sect = GetTemplateHeaderField(templatename, wxT("section"), true, idx); + if (sect.Length() == 0) + break; + /* extract the name, the side and the criterion */ + wxString name = GetToken(§); + wxString side = GetToken(§); + double crit; + sect.ToDouble(&crit); + sections[idx].SetCriterion(name, side, crit); + idx++; + } + } + /* clear any remaining sections */ + while (idx < (int)max) { + sections[idx].Clear(); + idx++; + } } bool ValidPinCount(long pins, const wxString& templatename, bool symbolmode) { - wxASSERT(templatename.length() > 0); - if (templatename.length() == 0 || pins == 0) - return false; - wxString field = GetTemplateHeaderField(templatename, wxT("pins"), symbolmode); - wxASSERT(symbolmode || field.length() > 0); /* if this header is absent, the field for - the number of pins is read-only for a footprint */ - if (field.length() == 0) - return symbolmode; /* for symbols, accept all pin counts if this field is absent */ - - long cur = 0, prev = 0; - int count = 0; - while (field.length() > 0) { - wxString item; - item = GetToken(&field); - if (item.Cmp(wxT("...")) == 0) { - if (count < 2) - return false; /* this means that the template definition is incorrect */ - long dif = cur - prev; - if (dif <= 0) - return false; /* again, template definition is incorrect */ - if (cur % dif == pins % dif) - return true; - } else { - prev = cur; - item.ToLong(&cur); - } - if (cur == pins) - return true; - if (cur > pins) - return false; /* no point in looking further */ - count++; - } - return false; + wxASSERT(templatename.length() > 0); + if (templatename.length() == 0 || pins == 0) + return false; + wxString field = GetTemplateHeaderField(templatename, wxT("pins"), symbolmode); + wxASSERT(symbolmode || field.length() > 0); /* if this header is absent, the field for + the number of pins is read-only for a footprint */ + if (field.length() == 0) + return symbolmode; /* for symbols, accept all pin counts if this field is absent */ + + long cur = 0, prev = 0; + int count = 0; + while (field.length() > 0) { + wxString item; + item = GetToken(&field); + if (item.Cmp(wxT("...")) == 0) { + if (count < 2) + return false; /* this means that the template definition is incorrect */ + long dif = cur - prev; + if (dif <= 0) + return false; /* again, template definition is incorrect */ + if (cur % dif == pins % dif) + return true; + } else { + prev = cur; + item.ToLong(&cur); + } + if (cur == pins) + return true; + if (cur > pins) + return false; /* no point in looking further */ + count++; + } + return false; } static const wxChar* rpn_errors[] = { wxT("(none)"), wxT("empty stack"), - wxT("multiple results"), wxT("underflow"), wxT("overflow"), - wxT("invalid variable"), wxT("invalid function"), wxT("invalid operator") }; + wxT("multiple results"), wxT("underflow"), wxT("overflow"), + wxT("invalid variable"), wxT("invalid function"), wxT("invalid operator") }; /* For footprints */ bool FootprintFromTemplate(wxArrayString* module, const wxArrayString& templat, - RPNexpression& rpn, bool bodyonly) + RPNexpression& rpn, bool bodyonly) { - int errorcount = 0; - - wxASSERT(module); - if (module->Count() < 3) - bodyonly = false; /* there cannot possibly be a valid module in so few lines */ - if (bodyonly) { - /* erase all lines up to the first pad */ - while (module->Item(0).CmpNoCase(wxT("$PAD")) != 0) - module->RemoveAt(0); - } else { - module->Clear(); - } - - /* the regular expression matches "{...}" where "..." is anything; this must - be a non-greedy match, because multiple expressions between braces can - exist on a single line */ - wxRegEx flt(wxT("\\{([^\\}]+?)\\}"), wxRE_ADVANCED); - wxASSERT(flt.IsValid()); - - wxString endlabel = wxEmptyString; - - /* copy the shape (body) */ - unsigned tidx = 0; - unsigned padstart = 0; - unsigned bodyline = 0; - while (tidx < templat.Count()) { - wxString line = templat[tidx]; - line.Trim(); - /* check for the start of a pad (pads are handled separately) */ - if (line.CmpNoCase(wxT("$PAD")) == 0 || line.Left(4).Cmp(wxT("(pad")) == 0) { - padstart = tidx; - break; - } - /* handle skipping conditional blocks */ - if (endlabel.length() > 0 || line[0] == wxT(':')) { - if (endlabel.length() > 0 && line.Cmp(endlabel) == 0) - endlabel = wxEmptyString; /* label matched, stop skipping */ - tidx++; - continue; - } - /* handle conditional expression */ - if (line[0] == wxT('{') && line[1] == wxT('?')) { - flt.Matches(line); - size_t start, len; - flt.GetMatch(&start, &len, 0); - wxASSERT(start == 0 && len > start && len <= line.length()); - wxASSERT(line[start + 1] == wxT('?')); - wxString expr = line.Mid(start + 2, len - 3); /* strip off {? and } */ - if (expr[0] == wxT(':')) { - /* there is an "end label" */ - for (start = 1; start < expr.length() && expr[start] > wxT(' '); start++) - /* nothing, skip the label name */; - endlabel = expr.Left(start); - expr = expr.Mid(start); - } - rpn.Set(expr.utf8_str()); - RPN_ERROR err = rpn.Parse(); - if (err == RPN_OK && rpn.Value().Double() < EPSILON) { - line = wxEmptyString; - } else { - line.replace(0, len, wxT("")); - endlabel = wxEmptyString; - } - } - for (int matchindex = 0; flt.Matches(line); matchindex++) { - size_t start, len; - flt.GetMatch(&start, &len, 0); - wxASSERT(len > 0 && start + len <= line.length()); - wxString expr = line.Mid(start + 1, len - 2); - rpn.Set(expr.utf8_str()); - RPN_ERROR err = rpn.Parse(); - if (err == RPN_OK) { - RPNvalue val = rpn.Value(); - if (val.Alpha()) { - expr = wxString::FromUTF8(val.Text()); - } else { - expr = wxString::Format(wxT("%.4f"), val.Double()); - StripTrailingZeros(&expr); - } - } else if (err == RPN_EMPTY) { - /* this means that the expression ended with an assignment */ - expr = wxEmptyString; - } else { - wxString msg = wxString::Format(wxT("RPN expression error \"%s\" on line %u, expression \"%s\""), - rpn_errors[err], tidx + 1, expr.c_str()); - wxMessageBox(msg); - expr = wxEmptyString; - errorcount++; - } - str_replace(line, start, len, expr); - } - line.Trim(); - if (line.length() > 0) - module->Insert(line, bodyline++); - tidx++; - } - if (endlabel.length() > 0) { - wxMessageBox(wxString::Format(wxT("RPN expression error: no match for label \"%s\""), endlabel.c_str())); - errorcount++; - } - - wxASSERT(padstart > 0); /* if it isn't, no pads are detected in the template, which is highly likely wrong */ - int tailstart = 0; - if (padstart > 0 && !bodyonly) { - /* get the number of pads defined for this shape */ - rpn.Set("PT"); - int pads = (rpn.Parse() == RPN_OK) ? (int)(rpn.Value().Double() + 0.1) : 0; /* + 0.1 to avoid rounding errors */ + int errorcount = 0; + + wxASSERT(module); + if (module->Count() < 3) + bodyonly = false; /* there cannot possibly be a valid module in so few lines */ + if (bodyonly) { + /* erase all lines up to the first pad */ + while (module->Item(0).CmpNoCase(wxT("$PAD")) != 0) + module->RemoveAt(0); + } else { + module->Clear(); + } + + /* the regular expression matches "{...}" where "..." is anything; this must + be a non-greedy match, because multiple expressions between braces can + exist on a single line */ + wxRegEx flt(wxT("\\{([^\\}]+?)\\}"), wxRE_ADVANCED); + wxASSERT(flt.IsValid()); + + wxString endlabel = wxEmptyString; + + /* copy the shape (body) */ + unsigned tidx = 0; + unsigned padstart = 0; + unsigned bodyline = 0; + while (tidx < templat.Count()) { + wxString line = templat[tidx]; + line.Trim(); + /* check for the start of a pad (pads are handled separately) */ + if (line.CmpNoCase(wxT("$PAD")) == 0 || line.Left(4).Cmp(wxT("(pad")) == 0) { + padstart = tidx; + break; + } + /* handle skipping conditional blocks */ + if (endlabel.length() > 0 || line[0] == wxT(':')) { + if (endlabel.length() > 0 && line.Cmp(endlabel) == 0) + endlabel = wxEmptyString; /* label matched, stop skipping */ + tidx++; + continue; + } + /* handle conditional expression */ + if (line[0] == wxT('{') && line[1] == wxT('?')) { + flt.Matches(line); + size_t start, len; + flt.GetMatch(&start, &len, 0); + wxASSERT(start == 0 && len > start && len <= line.length()); + wxASSERT(line[start + 1] == wxT('?')); + wxString expr = line.Mid(start + 2, len - 3); /* strip off {? and } */ + if (expr[0] == wxT(':')) { + /* there is an "end label" */ + for (start = 1; start < expr.length() && expr[start] > wxT(' '); start++) + /* nothing, skip the label name */; + endlabel = expr.Left(start); + expr = expr.Mid(start); + } + rpn.Set(expr.utf8_str()); + RPN_ERROR err = rpn.Parse(); + if (err == RPN_OK && rpn.Value().Double() < EPSILON) { + line = wxEmptyString; + } else { + line.replace(0, len, wxT("")); + endlabel = wxEmptyString; + } + } + for (int matchindex = 0; flt.Matches(line); matchindex++) { + size_t start, len; + flt.GetMatch(&start, &len, 0); + wxASSERT(len > 0 && start + len <= line.length()); + wxString expr = line.Mid(start + 1, len - 2); + rpn.Set(expr.utf8_str()); + RPN_ERROR err = rpn.Parse(); + if (err == RPN_OK) { + RPNvalue val = rpn.Value(); + if (val.Alpha()) { + expr = wxString::FromUTF8(val.Text()); + } else { + expr = wxString::Format(wxT("%.4f"), val.Double()); + StripTrailingZeros(&expr); + } + } else if (err == RPN_EMPTY) { + /* this means that the expression ended with an assignment */ + expr = wxEmptyString; + } else { + wxString msg = wxString::Format(wxT("RPN expression error \"%s\" on line %u, expression \"%s\""), + rpn_errors[err], tidx + 1, expr.c_str()); + wxMessageBox(msg); + expr = wxEmptyString; + errorcount++; + } + str_replace(line, start, len, expr); + } + line.Trim(); + if (line.length() > 0) + module->Insert(line, bodyline++); + tidx++; + } + if (endlabel.length() > 0) { + wxMessageBox(wxString::Format(wxT("RPN expression error: no match for label \"%s\""), endlabel.c_str())); + errorcount++; + } + + wxASSERT(padstart > 0); /* if it isn't, no pads are detected in the template, which is highly likely wrong */ + int tailstart = 0; + if (padstart > 0 && !bodyonly) { + /* get the number of pads defined for this shape */ + rpn.Set("PT"); + int pads = (rpn.Parse() == RPN_OK) ? (int)(rpn.Value().Double() + 0.1) : 0; /* + 0.1 to avoid rounding errors */ rpn.Set("PTA"); - int pads_aux = (rpn.Parse() == RPN_OK) ? (int)(rpn.Value().Double() + 0.1) : 0; /* + 0.1 to avoid rounding errors */ - for (int pad = 1; pad <= pads + pads_aux; pad++) { - endlabel = wxEmptyString; - tidx = padstart; - rpn.SetVariable(RPNvariable("PN", pad)); - while (tidx < templat.Count()) { - wxString line = templat[tidx]; - line.Trim(); - /* handle skipping conditional blocks */ - if (endlabel.length() > 0 || line[0] == wxT(':')) { - if (endlabel.length() > 0 && line.Cmp(endlabel) == 0) - endlabel = wxEmptyString; /* label matched, stop skipping */ - tidx++; - continue; - } - /* handle conditional expression */ - if (line[0] == wxT('{') && line[1] == wxT('?')) { - flt.Matches(line); - size_t start, len; - flt.GetMatch(&start, &len, 0); - wxASSERT(start == 0 && len > start && len <= line.length()); - wxASSERT(line[start + 1] == wxT('?')); - wxString expr = line.Mid(start + 2, len - 3); /* strip off {? and } */ - if (expr[0] == wxT(':')) { - /* there is an "end label" */ - for (start = 1; start < expr.length() && expr[start] > wxT(' '); start++) - /* nothing, skip the label name */; - endlabel = expr.Left(start); - expr = expr.Mid(start); - } - rpn.Set(expr.utf8_str()); - RPN_ERROR err = rpn.Parse(); - if (err == RPN_OK && rpn.Value().Double() < EPSILON) { - line = wxEmptyString; - } else { - line.replace(0, len, wxT("")); - endlabel = wxEmptyString; - } - } - for (int matchindex = 0; flt.Matches(line); matchindex++) { - size_t start, len; - flt.GetMatch(&start, &len, 0); - wxASSERT(len > 0 && start + len <= line.length()); - wxString expr = line.Mid(start + 1, len - 2); - /* there should not be any non-numeric expressions in a pad definition; - we do not handle them */ - rpn.Set(expr.utf8_str()); - RPN_ERROR err = rpn.Parse(); - if (err == RPN_OK) { - RPNvalue val = rpn.Value(); - if (val.Alpha()) { - expr = wxString::FromUTF8(val.Text()); - } else { - expr = wxString::Format(wxT("%.4f"), val.Double()); - StripTrailingZeros(&expr); - } - } else if (err == RPN_EMPTY) { - /* this means that the expression ended with an assignment */ - expr = wxEmptyString; - } else { - wxString msg = wxString::Format(wxT("RPN expression error \"%s\" on line %u, expression \"%s\""), - rpn_errors[err], tidx + 1, expr.c_str()); - wxMessageBox(msg); - expr = wxEmptyString; - errorcount++; - } - str_replace(line, start, len, expr); - } - line.Trim(); - if (line.length() > 0) - module->Add(line); - /* check for the end of a pad (templates in the s-expresssion format - must have the terminating ')' on a line of its own, and a parenthesis - on its own should never occur elsewhere within a pad definition) */ - line.Trim(false); - if (line.CmpNoCase(wxT("$EndPAD")) == 0 || line.Cmp(wxT(")")) == 0) { - tailstart = tidx + 1; - break; - } - tidx++; - } - if (endlabel.length() > 0) { - wxMessageBox(wxString::Format(wxT("RPN expression error: no match for label \"%s\""), endlabel.c_str())); - errorcount++; - } + int pads_aux = (rpn.Parse() == RPN_OK) ? (int)(rpn.Value().Double() + 0.1) : 0; /* + 0.1 to avoid rounding errors */ + for (int pad = 1; pad <= pads + pads_aux; pad++) { + endlabel = wxEmptyString; + tidx = padstart; + rpn.SetVariable(RPNvariable("PN", pad)); + while (tidx < templat.Count()) { + wxString line = templat[tidx]; + line.Trim(); + /* handle skipping conditional blocks */ + if (endlabel.length() > 0 || line[0] == wxT(':')) { + if (endlabel.length() > 0 && line.Cmp(endlabel) == 0) + endlabel = wxEmptyString; /* label matched, stop skipping */ + tidx++; + continue; + } + /* handle conditional expression */ + if (line[0] == wxT('{') && line[1] == wxT('?')) { + flt.Matches(line); + size_t start, len; + flt.GetMatch(&start, &len, 0); + wxASSERT(start == 0 && len > start && len <= line.length()); + wxASSERT(line[start + 1] == wxT('?')); + wxString expr = line.Mid(start + 2, len - 3); /* strip off {? and } */ + if (expr[0] == wxT(':')) { + /* there is an "end label" */ + for (start = 1; start < expr.length() && expr[start] > wxT(' '); start++) + /* nothing, skip the label name */; + endlabel = expr.Left(start); + expr = expr.Mid(start); + } + rpn.Set(expr.utf8_str()); + RPN_ERROR err = rpn.Parse(); + if (err == RPN_OK && rpn.Value().Double() < EPSILON) { + line = wxEmptyString; + } else { + line.replace(0, len, wxT("")); + endlabel = wxEmptyString; + } + } + for (int matchindex = 0; flt.Matches(line); matchindex++) { + size_t start, len; + flt.GetMatch(&start, &len, 0); + wxASSERT(len > 0 && start + len <= line.length()); + wxString expr = line.Mid(start + 1, len - 2); + /* there should not be any non-numeric expressions in a pad definition; + we do not handle them */ + rpn.Set(expr.utf8_str()); + RPN_ERROR err = rpn.Parse(); + if (err == RPN_OK) { + RPNvalue val = rpn.Value(); + if (val.Alpha()) { + expr = wxString::FromUTF8(val.Text()); + } else { + expr = wxString::Format(wxT("%.4f"), val.Double()); + StripTrailingZeros(&expr); + } + } else if (err == RPN_EMPTY) { + /* this means that the expression ended with an assignment */ + expr = wxEmptyString; + } else { + wxString msg = wxString::Format(wxT("RPN expression error \"%s\" on line %u, expression \"%s\""), + rpn_errors[err], tidx + 1, expr.c_str()); + wxMessageBox(msg); + expr = wxEmptyString; + errorcount++; + } + str_replace(line, start, len, expr); + } + line.Trim(); + if (line.length() > 0) + module->Add(line); + /* check for the end of a pad (templates in the s-expresssion format + must have the terminating ')' on a line of its own, and a parenthesis + on its own should never occur elsewhere within a pad definition) */ + line.Trim(false); + if (line.CmpNoCase(wxT("$EndPAD")) == 0 || line.Cmp(wxT(")")) == 0) { + tailstart = tidx + 1; + break; + } + tidx++; + } + if (endlabel.length() > 0) { + wxMessageBox(wxString::Format(wxT("RPN expression error: no match for label \"%s\""), endlabel.c_str())); + errorcount++; + } /* after running the first aux-pad, check the PTA variable again, - but note that the first aux-pad may be the last numbered pad (so + but note that the first aux-pad may be the last numbered pad (so the first aux-pad can be pads or pads + 1) */ if (pad >= pads) { rpn.Set("PTA"); - pads_aux = (rpn.Parse() == RPN_OK) ? (int)(rpn.Value().Double() + 0.1) : 0; /* + 0.1 to avoid rounding errors */ - } - } - } - - /* finish the template */ - endlabel = wxEmptyString; - wxASSERT(tailstart > 0 || bodyonly); /* there should be at least an $EndMODULE definition following the pads */ - if (tailstart > 0 && !bodyonly) { - tidx = tailstart; - while (tidx < templat.Count()) { - wxString line = templat[tidx]; - line.Trim(); - /* handle skipping conditional blocks */ - if (endlabel.length() > 0 || line[0] == wxT(':')) { - if (endlabel.length() > 0 && line.Cmp(endlabel) == 0) - endlabel = wxEmptyString; /* label matched, stop skipping */ - tidx++; - continue; - } - /* handle conditional expression */ - if (line[0] == wxT('{') && line[1] == wxT('?')) { - flt.Matches(line); - size_t start, len; - flt.GetMatch(&start, &len, 0); - wxASSERT(start == 0 && len > start && len <= line.length()); - wxASSERT(line[start + 1] == wxT('?')); - wxString expr = line.Mid(start + 2, len - 3); /* strip off {? and } */ - if (expr[0] == wxT(':')) { - /* there is an "end label" */ - for (start = 1; start < expr.length() && expr[start] > wxT(' '); start++) - /* nothing, skip the label name */; - endlabel = expr.Left(start); - expr = expr.Mid(start); - } - rpn.Set(expr.utf8_str()); - RPN_ERROR err = rpn.Parse(); - if (err == RPN_OK && rpn.Value().Double() < EPSILON) { - line = wxEmptyString; - } else { - line.replace(0, len, wxT("")); - endlabel = wxEmptyString; - } - } - for (int matchindex = 0; flt.Matches(line); matchindex++) { - size_t start, len; - flt.GetMatch(&start, &len, 0); - wxASSERT(len > 0 && start + len <= line.length()); - wxString expr = line.Mid(start + 1, len - 2); - rpn.Set(expr.utf8_str()); - RPN_ERROR err = rpn.Parse(); - if (err == RPN_OK) { - RPNvalue val = rpn.Value(); - if (val.Alpha()) { - expr = wxString::FromUTF8(val.Text()); - } else { - expr = wxString::Format(wxT("%.4f"), val.Double()); - StripTrailingZeros(&expr); - } - } else if (err == RPN_EMPTY) { - /* this means that the expression ended with an assignment */ - expr = wxEmptyString; - } else { - wxString msg = wxString::Format(wxT("RPN expression error \"%s\" on line %u, expression %s"), - rpn_errors[err], tidx + 1, expr.c_str()); - wxMessageBox(msg); - expr = wxEmptyString; - errorcount++; - } - str_replace(line, start, len, expr); - } - line.Trim(); - if (line.length() > 0) - module->Add(line); - tidx++; - } - if (endlabel.length() > 0) { - wxMessageBox(wxString::Format(wxT("RPN expression error: no match for label \"%s\""), endlabel.c_str())); - errorcount++; - } - } - - return errorcount == 0; + pads_aux = (rpn.Parse() == RPN_OK) ? (int)(rpn.Value().Double() + 0.1) : 0; /* + 0.1 to avoid rounding errors */ + } + } + } + + /* finish the template */ + endlabel = wxEmptyString; + wxASSERT(tailstart > 0 || bodyonly); /* there should be at least an $EndMODULE definition following the pads */ + if (tailstart > 0 && !bodyonly) { + tidx = tailstart; + while (tidx < templat.Count()) { + wxString line = templat[tidx]; + line.Trim(); + /* handle skipping conditional blocks */ + if (endlabel.length() > 0 || line[0] == wxT(':')) { + if (endlabel.length() > 0 && line.Cmp(endlabel) == 0) + endlabel = wxEmptyString; /* label matched, stop skipping */ + tidx++; + continue; + } + /* handle conditional expression */ + if (line[0] == wxT('{') && line[1] == wxT('?')) { + flt.Matches(line); + size_t start, len; + flt.GetMatch(&start, &len, 0); + wxASSERT(start == 0 && len > start && len <= line.length()); + wxASSERT(line[start + 1] == wxT('?')); + wxString expr = line.Mid(start + 2, len - 3); /* strip off {? and } */ + if (expr[0] == wxT(':')) { + /* there is an "end label" */ + for (start = 1; start < expr.length() && expr[start] > wxT(' '); start++) + /* nothing, skip the label name */; + endlabel = expr.Left(start); + expr = expr.Mid(start); + } + rpn.Set(expr.utf8_str()); + RPN_ERROR err = rpn.Parse(); + if (err == RPN_OK && rpn.Value().Double() < EPSILON) { + line = wxEmptyString; + } else { + line.replace(0, len, wxT("")); + endlabel = wxEmptyString; + } + } + for (int matchindex = 0; flt.Matches(line); matchindex++) { + size_t start, len; + flt.GetMatch(&start, &len, 0); + wxASSERT(len > 0 && start + len <= line.length()); + wxString expr = line.Mid(start + 1, len - 2); + rpn.Set(expr.utf8_str()); + RPN_ERROR err = rpn.Parse(); + if (err == RPN_OK) { + RPNvalue val = rpn.Value(); + if (val.Alpha()) { + expr = wxString::FromUTF8(val.Text()); + } else { + expr = wxString::Format(wxT("%.4f"), val.Double()); + StripTrailingZeros(&expr); + } + } else if (err == RPN_EMPTY) { + /* this means that the expression ended with an assignment */ + expr = wxEmptyString; + } else { + wxString msg = wxString::Format(wxT("RPN expression error \"%s\" on line %u, expression %s"), + rpn_errors[err], tidx + 1, expr.c_str()); + wxMessageBox(msg); + expr = wxEmptyString; + errorcount++; + } + str_replace(line, start, len, expr); + } + line.Trim(); + if (line.length() > 0) + module->Add(line); + tidx++; + } + if (endlabel.length() > 0) { + wxMessageBox(wxString::Format(wxT("RPN expression error: no match for label \"%s\""), endlabel.c_str())); + errorcount++; + } + } + + return errorcount == 0; } /* returns a full path to a VRML file, given a module (that contains a relative @@ -3055,969 +3055,969 @@ bool FootprintFromTemplate(wxArrayString* module, const wxArrayString& templat, For footprints and 3D models */ wxString GetVRMLPath(const wxString& library, const wxArrayString& module) { - wxString rpath = wxEmptyString; - - /* check that there is a VRML file in the module */ - bool in3dshape = false; - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - wxString token = GetToken(&line); - if (in3dshape && token.CmpNoCase(wxT("Na")) == 0) - rpath = GetToken(&line); - else if (token.Cmp(wxT("$SHAPE3D")) == 0) - in3dshape = true; - else if (token.Cmp(wxT("(module")) == 0) - rpath = GetToken(&line); - } - if (rpath.length() == 0) - return wxEmptyString; - - if (library.CmpNoCase(LIB_REPOS) == 0) { - /* for the repository, use only the base name of the library (ignore any - relative path in the module */ - int idx = rpath.Find('/', true); - if (idx < 0) - idx = rpath.Find('\\', true); - if (idx >= 0) - rpath = rpath.Mid(idx + 1); - } else { - /* for local libraries, first check whether the "relative" path actually is - an absolute path (there is nothing to do in that case) */ - if (rpath[0] != '/' && (rpath.length() < 3 || rpath[1] != ':' || (rpath[2] != '\\' && rpath[2] != '/'))) { - /* so it is a true relative path; strip the filename from the local - library path, add the "packages3d" path and the relative path */ - int idx = library.Find('/', true); - if (idx < 0) - idx = library.Find('\\', true); - if (idx >= 0) - rpath = library.Left(idx + 1) + wxT("packages3d/") + rpath; - } - /* adhere to the proper path separations */ - rpath.Replace(wxT("\\\\"), wxT("\\")); - #if DIRSEP_CHAR != '/' - rpath.Replace(wxT("/"), wxT(DIRSEP_STR)); - #endif - #if DIRSEP_CHAR != '\\' - rpath.Replace(wxT("\\"), wxT(DIRSEP_STR)); - #endif + wxString rpath = wxEmptyString; + + /* check that there is a VRML file in the module */ + bool in3dshape = false; + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + wxString token = GetToken(&line); + if (in3dshape && token.CmpNoCase(wxT("Na")) == 0) + rpath = GetToken(&line); + else if (token.Cmp(wxT("$SHAPE3D")) == 0) + in3dshape = true; + else if (token.Cmp(wxT("(module")) == 0) + rpath = GetToken(&line); + } + if (rpath.length() == 0) + return wxEmptyString; + + if (library.CmpNoCase(LIB_REPOS) == 0) { + /* for the repository, use only the base name of the library (ignore any + relative path in the module */ + int idx = rpath.Find('/', true); + if (idx < 0) + idx = rpath.Find('\\', true); + if (idx >= 0) + rpath = rpath.Mid(idx + 1); + } else { + /* for local libraries, first check whether the "relative" path actually is + an absolute path (there is nothing to do in that case) */ + if (rpath[0] != '/' && (rpath.length() < 3 || rpath[1] != ':' || (rpath[2] != '\\' && rpath[2] != '/'))) { + /* so it is a true relative path; strip the filename from the local + library path, add the "packages3d" path and the relative path */ + int idx = library.Find('/', true); + if (idx < 0) + idx = library.Find('\\', true); + if (idx >= 0) + rpath = library.Left(idx + 1) + wxT("packages3d/") + rpath; + } + /* adhere to the proper path separations */ + rpath.Replace(wxT("\\\\"), wxT("\\")); + #if DIRSEP_CHAR != '/' + rpath.Replace(wxT("/"), wxT(DIRSEP_STR)); + #endif + #if DIRSEP_CHAR != '\\' + rpath.Replace(wxT("\\"), wxT(DIRSEP_STR)); + #endif /* add the extension, if not present */ if (rpath.Length() < 4 || rpath.Right(4).CmpNoCase(wxT(".wrl")) != 0) rpath = rpath + wxT(".wrl"); - } + } + + return rpath; +} + +/* For footprintts and 3D models */ +bool CopyVRMLfile(const wxString& source, const wxString& target, + const wxString& author, const wxArrayString& module) +{ + wxString sourcepath = GetVRMLPath(source, module); + if (sourcepath.Length() == 0) + return false; + wxString targetpath = GetVRMLPath(target, module); + wxASSERT(targetpath.length() > 0); /* if there is a source path, there must be a target path */ + if (sourcepath.Cmp(targetpath) == 0) + return false; /* source and target point to the same filename (or repository entry) */ + if (!wxFileExists(sourcepath)) + return false; + + bool result = false; + if (source.CmpNoCase(LIB_REPOS) == 0) { + #if !defined NO_CURL + /* get the model */ + wxArrayString model; + wxString msg = curlGet(sourcepath, author, wxT("models"), &model); + if (msg.length() == 0) { + /* write the model to file */ + wxTextFile file; + if (file.Open(sourcepath) || file.Create(sourcepath)) { + file.Clear(); /* delete any existing contents */ + for (unsigned idx = 0; idx < model.Count(); idx++) + file.AddLine(model[idx]); + file.Write(); + file.Close(); + result = true; + } + } + #endif + } else if (target.CmpNoCase(LIB_REPOS) == 0) { + #if !defined NO_CURL + /* load the model */ + wxArrayString model; + wxTextFile file; + if (file.Open(sourcepath)) { + for (unsigned idx = 0; idx < file.GetLineCount(); idx++) { + wxString line = file.GetLine(idx); + line.Trim(); + line.Trim(false); + model.Add(line); + } + file.Close(); + /* upload the model */ + wxString msg = curlPut(targetpath, wxT("models"), model); + if (msg.length() == 0) + result = true; + } + #endif + } else { + /* check whether to create the path */ + wxFileName fname(targetpath); + if (!wxDirExists(fname.GetPath())) + wxFileName::Mkdir(fname.GetPath(), 0777, wxPATH_MKDIR_FULL); + result = ::wxCopyFile(sourcepath, targetpath); + } + return result; +} + +/* VRMLFromTemplate() creates the 3d model from a template and a fully + initialized RPN engine --the routine gets the pin count from the "PT" + variable */ +bool VRMLFromTemplate(const wxString vrmlpath, const wxString& templatename, RPNexpression& rpn) +{ + /* create full path to the template */ + wxString templatepath = theApp->GetTemplatePath() + wxT(DIRSEP_STR) + templatename + wxT(".vt"); + + /* load the template */ + wxTextFile file; + if (!file.Open(templatepath)) + return false; + wxArrayString templat; + for (unsigned idx = 0; idx < file.GetLineCount(); idx++) { + wxString line = file.GetLine(idx); + line.Trim(); + templat.Add(line); + } + file.Close(); + + /* run over the template, create the output */ + + /* the regular expression matches "{...}" where "..." is anything; this must + be a non-greedy match, because multiple expressions between braces can + exist on a single line */ + wxRegEx flt(wxT("\\{([^ ][^\\}]+?)\\}"), wxRE_ADVANCED); + wxASSERT(flt.IsValid()); + + wxString endlabel = wxEmptyString; + int errorcount = 0; + wxArrayString model; + + /* copy the body */ + bool inside_pins = false; + unsigned tidx = 0; + while (tidx < templat.Count()) { + wxString line = templat[tidx]; + if (line.Length() == 0) { + tidx++; + continue; + } + /* copy up to the line "Shape {" inside the "DEF pins Transform {" section, + which means that the "DEF pins" must be found first */ + if (line.Left(8).CmpNoCase(wxT("DEF pins")) == 0) + inside_pins = true; + if (inside_pins) { + wxString trimmed = line; + trimmed.Trim(false); + if (trimmed.CmpNoCase(wxT("Shape {")) == 0) + break; + } + /* handle skipping conditional blocks */ + if (endlabel.length() > 0 || line[0] == wxT(':')) { + if (endlabel.length() > 0 && line.Cmp(endlabel) == 0) + endlabel = wxEmptyString; /* label matched, stop skipping */ + tidx++; + continue; + } + /* handle conditional expression */ + if (line[0] == wxT('{') && line[1] == wxT('?')) { + flt.Matches(line); + size_t start, len; + flt.GetMatch(&start, &len, 0); + wxASSERT(start == 0 && len > start && len <= line.length()); + wxASSERT(line[start + 1] == wxT('?')); + wxString expr = line.Mid(start + 2, len - 3); /* strip off {? and } */ + if (expr[0] == wxT(':')) { + /* there is an "end label" */ + for (start = 1; start < expr.length() && expr[start] > wxT(' '); start++) + /* nothing, skip the label name */; + endlabel = expr.Left(start); + expr = expr.Mid(start); + } + rpn.Set(expr.utf8_str()); + RPN_ERROR err = rpn.Parse(); + if (err == RPN_OK && rpn.Value().Double() < EPSILON) { + line = wxEmptyString; + } else { + line.replace(0, len, wxT("")); + endlabel = wxEmptyString; + } + } + for (int matchindex = 0; flt.Matches(line); matchindex++) { + size_t start, len; + flt.GetMatch(&start, &len, 0); + wxASSERT(len > 0 && start + len <= line.length()); + wxString expr = line.Mid(start + 1, len - 2); + rpn.Set(expr.utf8_str()); + RPN_ERROR err = rpn.Parse(); + if (err == RPN_OK) { + RPNvalue val = rpn.Value(); + if (val.Alpha()) { + expr = wxString::FromUTF8(val.Text()); + } else { + expr = wxString::Format(wxT("%.4f"), val.Double()); + StripTrailingZeros(&expr); + } + } else if (err == RPN_EMPTY) { + /* this means that the expression ended with an assignment */ + expr = wxEmptyString; + } else { + wxString msg = wxString::Format(wxT("RPN expression error \"%s\" on line %u, expression \"%s\""), + rpn_errors[err], tidx + 1, expr.c_str()); + wxMessageBox(msg); + expr = wxEmptyString; + errorcount++; + } + str_replace(line, start, len, expr); + } + line.Trim(); + if (line.length() > 0) + model.Add(line); + tidx++; + } + if (endlabel.length() > 0) { + wxMessageBox(wxString::Format(wxT("RPN expression error: no match for label \"%s\""), endlabel.c_str())); + errorcount++; + } + + /* update the "model" line in the header, to specify options (height) */ + if (rpn.ExistVariable("BH")) { + rpn.Set("BH"); + if (rpn.Parse() == RPN_OK) { + for (unsigned idx = 0; idx < model.Count(); idx++) { + wxASSERT(model[idx].Length() > 0); /* zero-length lines are not added to the output */ + if (model[idx].Left(6).Cmp(wxT("#model")) == 0) { + model[idx] += wxString::Format(wxT(" {height %.1f}"), rpn.Value().Double()); + break; /* no need to search further */ + } + } + } + } + + /* repeat for every pin */ + long pins = 0; + if (rpn.ExistVariable("PT")) { + rpn.Set("PT"); + if (rpn.Parse() == RPN_OK) + pins = (long)(rpn.Value().Double() + 0.1); + } + unsigned pins_start = tidx; + unsigned pins_end = 0; + for (long pin = 1; pin <= pins; pin++) { + tidx = pins_start; + rpn.SetVariable(RPNvariable("PN", (double)pin)); + while (tidx < templat.Count()) { + wxString line = templat[tidx]; + /* copy up to a line with only a "]" */ + wxString trimmed = line; + trimmed.Trim(false); + if (trimmed.Cmp(wxT("]")) == 0) { + pins_end = tidx; + break; + } + /* handle skipping conditional blocks */ + if (endlabel.length() > 0 || line[0] == wxT(':')) { + if (endlabel.length() > 0 && line.Cmp(endlabel) == 0) + endlabel = wxEmptyString; /* label matched, stop skipping */ + tidx++; + continue; + } + /* handle conditional expression */ + if (trimmed[0] == wxT('{') && trimmed[1] == wxT('?') && flt.Matches(line)) { + size_t start, len; + flt.GetMatch(&start, &len, 0); + wxASSERT(start + len <= line.length()); + wxASSERT(line[start + 1] == wxT('?')); + wxString expr = line.Mid(start + 2, len - 3); /* strip off {? and } */ + if (expr[0] == wxT(':')) { + /* there is an "end label" */ + unsigned idx; + for (idx = 1; idx < expr.length() && expr[idx] > wxT(' '); idx++) + /* nothing, skip the label name */; + endlabel = expr.Left(idx); + expr = expr.Mid(idx); + } + rpn.Set(expr.utf8_str()); + RPN_ERROR err = rpn.Parse(); + if (err == RPN_OK && rpn.Value().Double() < EPSILON) { + line = wxEmptyString; + } else { + line.replace(start, len, wxT("")); + endlabel = wxEmptyString; + } + } + for (int matchindex = 0; flt.Matches(line); matchindex++) { + size_t start, len; + flt.GetMatch(&start, &len, 0); + wxASSERT(len > 0 && start + len <= line.length()); + wxString expr = line.Mid(start + 1, len - 2); + rpn.Set(expr.utf8_str()); + RPN_ERROR err = rpn.Parse(); + if (err == RPN_OK) { + RPNvalue val = rpn.Value(); + if (val.Alpha()) { + expr = wxString::FromUTF8(val.Text()); + } else { + expr = wxString::Format(wxT("%.4f"), val.Double()); + StripTrailingZeros(&expr); + } + } else if (err == RPN_EMPTY) { + /* this means that the expression ended with an assignment */ + expr = wxEmptyString; + } else { + wxString msg = wxString::Format(wxT("RPN expression error \"%s\" on line %u, expression \"%s\""), + rpn_errors[err], tidx + 1, expr.c_str()); + wxMessageBox(msg); + expr = wxEmptyString; + errorcount++; + } + str_replace(line, start, len, expr); + } + line.Trim(); + if (line.length() > 0) + model.Add(line); + tidx++; + } + if (endlabel.length() > 0) { + wxMessageBox(wxString::Format(wxT("RPN expression error: no match for label \"%s\""), endlabel.c_str())); + errorcount++; + } + } + + /* copy the trailer, a simple loop that does not consider expressions */ + for (tidx = pins_end; tidx < templat.Count(); tidx++) { + wxString line = templat[tidx]; + line.Trim(); + if (line.length() > 0) + model.Add(line); + } + + if (errorcount>0) + return false; /* message already given */ + + /* check whether to create the path */ + wxFileName fname(vrmlpath); + if (!wxDirExists(fname.GetPath())) + wxFileName::Mkdir(fname.GetPath(), 0777, wxPATH_MKDIR_FULL); + + /* save the output */ + if (wxFileExists(vrmlpath)) + wxRemoveFile(vrmlpath); + if (!file.Create(vrmlpath)) { + wxMessageBox(wxString::Format(wxT("Failed to create file \"%s\""), vrmlpath.c_str())); + return false; + } + for (unsigned tidx = 0; tidx < model.Count(); tidx++) + file.AddLine(model[tidx]); + file.Write(); + file.Close(); - return rpath; + return true; } -/* For footprintts and 3D models */ -bool CopyVRMLfile(const wxString& source, const wxString& target, - const wxString& author, const wxArrayString& module) +/* For symbols */ +bool SymbolFromTemplate(wxArrayString* symbol, const wxArrayString& templat, + RPNexpression& rpn, const PinInfo* pininfo, int pincount) { - wxString sourcepath = GetVRMLPath(source, module); - if (sourcepath.Length() == 0) - return false; - wxString targetpath = GetVRMLPath(target, module); - wxASSERT(targetpath.length() > 0); /* if there is a source path, there must be a target path */ - if (sourcepath.Cmp(targetpath) == 0) - return false; /* source and target point to the same filename (or repository entry) */ - if (!wxFileExists(sourcepath)) - return false; - - bool result = false; - if (source.CmpNoCase(LIB_REPOS) == 0) { - #if !defined NO_CURL - /* get the model */ - wxArrayString model; - wxString msg = curlGet(sourcepath, author, wxT("models"), &model); - if (msg.length() == 0) { - /* write the model to file */ - wxTextFile file; - if (file.Open(sourcepath) || file.Create(sourcepath)) { - file.Clear(); /* delete any existing contents */ - for (unsigned idx = 0; idx < model.Count(); idx++) - file.AddLine(model[idx]); - file.Write(); - file.Close(); - result = true; - } - } - #endif - } else if (target.CmpNoCase(LIB_REPOS) == 0) { - #if !defined NO_CURL - /* load the model */ - wxArrayString model; - wxTextFile file; - if (file.Open(sourcepath)) { - for (unsigned idx = 0; idx < file.GetLineCount(); idx++) { - wxString line = file.GetLine(idx); - line.Trim(); - line.Trim(false); - model.Add(line); - } - file.Close(); - /* upload the model */ - wxString msg = curlPut(targetpath, wxT("models"), model); - if (msg.length() == 0) - result = true; - } - #endif - } else { - /* check whether to create the path */ - wxFileName fname(targetpath); - if (!wxDirExists(fname.GetPath())) - wxFileName::Mkdir(fname.GetPath(), 0777, wxPATH_MKDIR_FULL); - result = ::wxCopyFile(sourcepath, targetpath); - } - return result; -} + int errorcount = 0; + + wxASSERT(symbol != NULL); + symbol->Clear(); + + /* update variables on the count of pins per section (when the pins are + re-assigned to other sections, the counts may no longer be correct) */ + wxASSERT(pininfo != NULL); + int pcnt[PinInfo::SectionCount]; + for (int s = 0; s < PinInfo::SectionCount; s++) { + int count = 0; + for (int p = 0; p < pincount; p++) + if (pininfo[p].section == s && pininfo[p].type != PinInfo::NC) + count++; + char varname[20]; + sprintf(varname, "PT:%d", s); + rpn.SetVariable(RPNvariable(varname, count)); + pcnt[s] = count; + } -/* VRMLFromTemplate() creates the 3d model from a template and a fully - initialized RPN engine --the routine gets the pin count from the "PT" - variable */ -bool VRMLFromTemplate(const wxString vrmlpath, const wxString& templatename, RPNexpression& rpn) -{ - /* create full path to the template */ - wxString templatepath = theApp->GetTemplatePath() + wxT(DIRSEP_STR) + templatename + wxT(".vt"); - - /* load the template */ - wxTextFile file; - if (!file.Open(templatepath)) - return false; - wxArrayString templat; - for (unsigned idx = 0; idx < file.GetLineCount(); idx++) { - wxString line = file.GetLine(idx); - line.Trim(); - templat.Add(line); - } - file.Close(); - - /* run over the template, create the output */ - - /* the regular expression matches "{...}" where "..." is anything; this must - be a non-greedy match, because multiple expressions between braces can - exist on a single line */ - wxRegEx flt(wxT("\\{([^ ][^\\}]+?)\\}"), wxRE_ADVANCED); - wxASSERT(flt.IsValid()); - - wxString endlabel = wxEmptyString; - int errorcount = 0; - wxArrayString model; - - /* copy the body */ - bool inside_pins = false; - unsigned tidx = 0; - while (tidx < templat.Count()) { - wxString line = templat[tidx]; - if (line.Length() == 0) { + /* the regular expression matches "{...}" where "..." is anything; this must + be a non-greedy match, because multiple expressions between braces can + exist on a single line */ + wxRegEx flt(wxT("\\{([^\\}]+?)\\}"), wxRE_ADVANCED); + wxASSERT(flt.IsValid()); + + wxString endlabel = wxEmptyString; + + /* copy the shape */ + unsigned tidx = 0; + unsigned drawstart = 0; + unsigned drawend = 0; + int pinidx = 0; + while (tidx < templat.Count()) { + wxString line = templat[tidx]; + line.Trim(); + /* handle skipping conditional blocks */ + if (endlabel.length() > 0 || line[0] == wxT(':')) { + if (endlabel.length() > 0 && line.Cmp(endlabel) == 0) + endlabel = wxEmptyString; /* label matched, stop skipping */ tidx++; continue; } - /* copy up to the line "Shape {" inside the "DEF pins Transform {" section, - which means that the "DEF pins" must be found first */ - if (line.Left(8).CmpNoCase(wxT("DEF pins")) == 0) - inside_pins = true; - if (inside_pins) { - wxString trimmed = line; - trimmed.Trim(false); - if (trimmed.CmpNoCase(wxT("Shape {")) == 0) - break; - } - /* handle skipping conditional blocks */ - if (endlabel.length() > 0 || line[0] == wxT(':')) { - if (endlabel.length() > 0 && line.Cmp(endlabel) == 0) - endlabel = wxEmptyString; /* label matched, stop skipping */ - tidx++; - continue; - } - /* handle conditional expression */ - if (line[0] == wxT('{') && line[1] == wxT('?')) { - flt.Matches(line); - size_t start, len; - flt.GetMatch(&start, &len, 0); - wxASSERT(start == 0 && len > start && len <= line.length()); - wxASSERT(line[start + 1] == wxT('?')); - wxString expr = line.Mid(start + 2, len - 3); /* strip off {? and } */ - if (expr[0] == wxT(':')) { - /* there is an "end label" */ - for (start = 1; start < expr.length() && expr[start] > wxT(' '); start++) - /* nothing, skip the label name */; - endlabel = expr.Left(start); - expr = expr.Mid(start); - } - rpn.Set(expr.utf8_str()); - RPN_ERROR err = rpn.Parse(); - if (err == RPN_OK && rpn.Value().Double() < EPSILON) { - line = wxEmptyString; - } else { - line.replace(0, len, wxT("")); - endlabel = wxEmptyString; - } - } - for (int matchindex = 0; flt.Matches(line); matchindex++) { - size_t start, len; - flt.GetMatch(&start, &len, 0); - wxASSERT(len > 0 && start + len <= line.length()); - wxString expr = line.Mid(start + 1, len - 2); - rpn.Set(expr.utf8_str()); - RPN_ERROR err = rpn.Parse(); - if (err == RPN_OK) { - RPNvalue val = rpn.Value(); - if (val.Alpha()) { - expr = wxString::FromUTF8(val.Text()); - } else { - expr = wxString::Format(wxT("%.4f"), val.Double()); - StripTrailingZeros(&expr); - } - } else if (err == RPN_EMPTY) { - /* this means that the expression ended with an assignment */ - expr = wxEmptyString; - } else { - wxString msg = wxString::Format(wxT("RPN expression error \"%s\" on line %u, expression \"%s\""), - rpn_errors[err], tidx + 1, expr.c_str()); - wxMessageBox(msg); - expr = wxEmptyString; - errorcount++; - } - str_replace(line, start, len, expr); - } - line.Trim(); - if (line.length() > 0) - model.Add(line); - tidx++; - } - if (endlabel.length() > 0) { - wxMessageBox(wxString::Format(wxT("RPN expression error: no match for label \"%s\""), endlabel.c_str())); - errorcount++; - } - - /* update the "model" line in the header, to specify options (height) */ - if (rpn.ExistVariable("BH")) { - rpn.Set("BH"); - if (rpn.Parse() == RPN_OK) { - for (unsigned idx = 0; idx < model.Count(); idx++) { - wxASSERT(model[idx].Length() > 0); /* zero-length lines are not added to the output */ - if (model[idx].Left(6).Cmp(wxT("#model")) == 0) { - model[idx] += wxString::Format(wxT(" {height %.1f}"), rpn.Value().Double()); - break; /* no need to search further */ + /* handle conditional expression */ + if (line[0] == wxT('{') && line[1] == wxT('?')) { + flt.Matches(line); + size_t start, len; + flt.GetMatch(&start, &len, 0); + wxASSERT(start == 0 && len > start && len <= line.length()); + wxASSERT(line[start + 1] == wxT('?')); + wxString expr = line.Mid(start + 2, len - 3); /* strip off {? and } */ + if (expr[0] == wxT(':')) { + /* there is an "end label" */ + for (start = 1; start < expr.length() && expr[start] > wxT(' '); start++) + /* nothing, skip the label name */; + endlabel = expr.Left(start); + expr = expr.Mid(start); + } + rpn.Set(expr.utf8_str()); + RPN_ERROR err = rpn.Parse(); + if (err == RPN_OK && rpn.Value().Double() < EPSILON) { + line = wxEmptyString; + } else { + line.replace(0, len, wxT("")); + endlabel = wxEmptyString; + } + } + /* check for the start of a drawing section or whether we are inside a + drawing section (because the pins need to be repeated) */ + if (line.Cmp(wxT("DRAW")) == 0) { + drawstart = tidx; + wxASSERT(pininfo != NULL); + wxASSERT(pincount > 0 && pinidx < pincount); + rpn.SetVariable(RPNvariable("PS", pininfo[pinidx].section)); /* side/section */ + rpn.SetVariable(RPNvariable("PTS", pcnt[pininfo[pinidx].section])); + int pinseq = 0; + for (int i = 0; i < pinidx; i++) + if (pininfo[i].section == pininfo[pinidx].section && pininfo[i].type != PinInfo::NC) + pinseq++; + rpn.SetVariable(RPNvariable("PNS", pinseq + 1)); /* sequence number in the section */ + rpn.SetVariable(RPNvariable("PLB", pininfo[pinidx].name.utf8_str())); + rpn.SetVariable(RPNvariable("PN", pininfo[pinidx].number.utf8_str())); + static const char *type[] = { "I", "O", "B", "T", "P", "C", "E", "N", "U", "W", "w" }; + rpn.SetVariable(RPNvariable("PTY", type[pininfo[pinidx].type])); + static const char *shape[] = { "", "I", "C", "CI", "" }; + rpn.SetVariable(RPNvariable("PSH", shape[pininfo[pinidx].shape])); + if (pinidx > 0) { /* output the line "DRAW" only once */ + tidx++; + continue; + } + } else if (line.Cmp(wxT("ENDDRAW")) == 0) { + drawend = tidx; + pinidx++; + /* check whether we have handled all pins; if not, repeat */ + if (pinidx < pincount) { + tidx = drawstart; /* drop back to read "DRAW" on the next iteration, which + will adjust the variables */ + continue; + } + } else if (tidx >= drawstart && tidx < drawend && pinidx > 0) { + /* on the second, third, ... passes through the DRAW section, ignore all + commands except X and calculations */ + if (line.Length() == 0 || (line.Left(2).Cmp(wxT("X ")) != 0 && line[0] != wxT('{'))) { + tidx++; + continue; + } + } + for (int matchindex = 0; flt.Matches(line); matchindex++) { + size_t start, len; + flt.GetMatch(&start, &len, 0); + wxASSERT(len > 0 && start + len <= line.length()); + wxString expr = line.Mid(start + 1, len - 2); + rpn.Set(expr.utf8_str()); + RPN_ERROR err = rpn.Parse(); + if (err == RPN_OK) { + RPNvalue val = rpn.Value(); + if (val.Alpha()) { + expr = wxString::FromUTF8(val.Text()); + } else { + expr = wxString::Format(wxT("%.4f"), val.Double()); + StripTrailingZeros(&expr); } + } else if (err == RPN_EMPTY) { + /* this means that the expression ended with an assignment */ + expr = wxEmptyString; + } else { + wxString msg = wxString::Format(wxT("RPN expression error \"%s\" on line %u, expression \"%s\""), + rpn_errors[err], tidx + 1, expr.c_str()); + wxMessageBox(msg); + expr = wxEmptyString; + errorcount++; } + str_replace(line, start, len, expr); } - } - - /* repeat for every pin */ - long pins = 0; - if (rpn.ExistVariable("PT")) { - rpn.Set("PT"); - if (rpn.Parse() == RPN_OK) - pins = (long)(rpn.Value().Double() + 0.1); - } - unsigned pins_start = tidx; - unsigned pins_end = 0; - for (long pin = 1; pin <= pins; pin++) { - tidx = pins_start; - rpn.SetVariable(RPNvariable("PN", (double)pin)); - while (tidx < templat.Count()) { - wxString line = templat[tidx]; - /* copy up to a line with only a "]" */ - wxString trimmed = line; - trimmed.Trim(false); - if (trimmed.Cmp(wxT("]")) == 0) { - pins_end = tidx; - break; - } - /* handle skipping conditional blocks */ - if (endlabel.length() > 0 || line[0] == wxT(':')) { - if (endlabel.length() > 0 && line.Cmp(endlabel) == 0) - endlabel = wxEmptyString; /* label matched, stop skipping */ - tidx++; - continue; - } - /* handle conditional expression */ - if (trimmed[0] == wxT('{') && trimmed[1] == wxT('?') && flt.Matches(line)) { - size_t start, len; - flt.GetMatch(&start, &len, 0); - wxASSERT(start + len <= line.length()); - wxASSERT(line[start + 1] == wxT('?')); - wxString expr = line.Mid(start + 2, len - 3); /* strip off {? and } */ - if (expr[0] == wxT(':')) { - /* there is an "end label" */ - unsigned idx; - for (idx = 1; idx < expr.length() && expr[idx] > wxT(' '); idx++) - /* nothing, skip the label name */; - endlabel = expr.Left(idx); - expr = expr.Mid(idx); - } - rpn.Set(expr.utf8_str()); - RPN_ERROR err = rpn.Parse(); - if (err == RPN_OK && rpn.Value().Double() < EPSILON) { - line = wxEmptyString; - } else { - line.replace(start, len, wxT("")); - endlabel = wxEmptyString; - } - } - for (int matchindex = 0; flt.Matches(line); matchindex++) { - size_t start, len; - flt.GetMatch(&start, &len, 0); - wxASSERT(len > 0 && start + len <= line.length()); - wxString expr = line.Mid(start + 1, len - 2); - rpn.Set(expr.utf8_str()); - RPN_ERROR err = rpn.Parse(); - if (err == RPN_OK) { - RPNvalue val = rpn.Value(); - if (val.Alpha()) { - expr = wxString::FromUTF8(val.Text()); - } else { - expr = wxString::Format(wxT("%.4f"), val.Double()); - StripTrailingZeros(&expr); - } - } else if (err == RPN_EMPTY) { - /* this means that the expression ended with an assignment */ - expr = wxEmptyString; - } else { - wxString msg = wxString::Format(wxT("RPN expression error \"%s\" on line %u, expression \"%s\""), - rpn_errors[err], tidx + 1, expr.c_str()); - wxMessageBox(msg); - expr = wxEmptyString; - errorcount++; - } - str_replace(line, start, len, expr); - } - line.Trim(); - if (line.length() > 0) - model.Add(line); - tidx++; - } - if (endlabel.length() > 0) { - wxMessageBox(wxString::Format(wxT("RPN expression error: no match for label \"%s\""), endlabel.c_str())); - errorcount++; - } - } - - /* copy the trailer, a simple loop that does not consider expressions */ - for (tidx = pins_end; tidx < templat.Count(); tidx++) { - wxString line = templat[tidx]; - line.Trim(); - if (line.length() > 0) - model.Add(line); - } - - if (errorcount>0) - return false; /* message already given */ - - /* check whether to create the path */ - wxFileName fname(vrmlpath); - if (!wxDirExists(fname.GetPath())) - wxFileName::Mkdir(fname.GetPath(), 0777, wxPATH_MKDIR_FULL); - - /* save the output */ - if (wxFileExists(vrmlpath)) - wxRemoveFile(vrmlpath); - if (!file.Create(vrmlpath)) { - wxMessageBox(wxString::Format(wxT("Failed to create file \"%s\""), vrmlpath.c_str())); - return false; - } - for (unsigned tidx = 0; tidx < model.Count(); tidx++) - file.AddLine(model[tidx]); - file.Write(); - file.Close(); - - return true; -} + line.Trim(); + if (line.length() > 0) + symbol->Add(line); + tidx++; + } + if (endlabel.length() > 0) { + wxMessageBox(wxString::Format(wxT("RPN expression error: no match for label \"%s\""), endlabel.c_str())); + errorcount++; + } -/* For symbols */ -bool SymbolFromTemplate(wxArrayString* symbol, const wxArrayString& templat, - RPNexpression& rpn, const PinInfo* pininfo, int pincount) -{ - int errorcount = 0; - - wxASSERT(symbol != NULL); - symbol->Clear(); - - /* update variables on the count of pins per section (when the pins are - re-assigned to other sections, the counts may no longer be correct) */ - wxASSERT(pininfo != NULL); - int pcnt[PinInfo::SectionCount]; - for (int s = 0; s < PinInfo::SectionCount; s++) { - int count = 0; - for (int p = 0; p < pincount; p++) - if (pininfo[p].section == s && pininfo[p].type != PinInfo::NC) - count++; - char varname[20]; - sprintf(varname, "PT:%d", s); - rpn.SetVariable(RPNvariable(varname, count)); - pcnt[s] = count; - } - - /* the regular expression matches "{...}" where "..." is anything; this must - be a non-greedy match, because multiple expressions between braces can - exist on a single line */ - wxRegEx flt(wxT("\\{([^\\}]+?)\\}"), wxRE_ADVANCED); - wxASSERT(flt.IsValid()); - - wxString endlabel = wxEmptyString; - - /* copy the shape */ - unsigned tidx = 0; - unsigned drawstart = 0; - unsigned drawend = 0; - int pinidx = 0; - while (tidx < templat.Count()) { - wxString line = templat[tidx]; - line.Trim(); - /* handle skipping conditional blocks */ - if (endlabel.length() > 0 || line[0] == wxT(':')) { - if (endlabel.length() > 0 && line.Cmp(endlabel) == 0) - endlabel = wxEmptyString; /* label matched, stop skipping */ - tidx++; - continue; - } - /* handle conditional expression */ - if (line[0] == wxT('{') && line[1] == wxT('?')) { - flt.Matches(line); - size_t start, len; - flt.GetMatch(&start, &len, 0); - wxASSERT(start == 0 && len > start && len <= line.length()); - wxASSERT(line[start + 1] == wxT('?')); - wxString expr = line.Mid(start + 2, len - 3); /* strip off {? and } */ - if (expr[0] == wxT(':')) { - /* there is an "end label" */ - for (start = 1; start < expr.length() && expr[start] > wxT(' '); start++) - /* nothing, skip the label name */; - endlabel = expr.Left(start); - expr = expr.Mid(start); - } - rpn.Set(expr.utf8_str()); - RPN_ERROR err = rpn.Parse(); - if (err == RPN_OK && rpn.Value().Double() < EPSILON) { - line = wxEmptyString; - } else { - line.replace(0, len, wxT("")); - endlabel = wxEmptyString; - } - } - /* check for the start of a drawing section or whether we are inside a - drawing section (because the pins need to be repeated) */ - if (line.Cmp(wxT("DRAW")) == 0) { - drawstart = tidx; - wxASSERT(pininfo != NULL); - wxASSERT(pincount > 0 && pinidx < pincount); - rpn.SetVariable(RPNvariable("PS", pininfo[pinidx].section)); /* side/section */ - rpn.SetVariable(RPNvariable("PTS", pcnt[pininfo[pinidx].section])); - int pinseq = 0; - for (int i = 0; i < pinidx; i++) - if (pininfo[i].section == pininfo[pinidx].section && pininfo[i].type != PinInfo::NC) - pinseq++; - rpn.SetVariable(RPNvariable("PNS", pinseq + 1)); /* sequence number in the section */ - rpn.SetVariable(RPNvariable("PLB", pininfo[pinidx].name.utf8_str())); - rpn.SetVariable(RPNvariable("PN", pininfo[pinidx].number.utf8_str())); - static const char *type[] = { "I", "O", "B", "T", "P", "C", "E", "N", "U", "W", "w" }; - rpn.SetVariable(RPNvariable("PTY", type[pininfo[pinidx].type])); - static const char *shape[] = { "", "I", "C", "CI", "" }; - rpn.SetVariable(RPNvariable("PSH", shape[pininfo[pinidx].shape])); - if (pinidx > 0) { /* output the line "DRAW" only once */ - tidx++; - continue; - } - } else if (line.Cmp(wxT("ENDDRAW")) == 0) { - drawend = tidx; - pinidx++; - /* check whether we have handled all pins; if not, repeat */ - if (pinidx < pincount) { - tidx = drawstart; /* drop back to read "DRAW" on the next iteration, which - will adjust the variables */ - continue; - } - } else if (tidx >= drawstart && tidx < drawend && pinidx > 0) { - /* on the second, third, ... passes through the DRAW section, ignore all - commands except X and calculations */ - if (line.Length() == 0 || (line.Left(2).Cmp(wxT("X ")) != 0 && line[0] != wxT('{'))) { - tidx++; - continue; - } - } - for (int matchindex = 0; flt.Matches(line); matchindex++) { - size_t start, len; - flt.GetMatch(&start, &len, 0); - wxASSERT(len > 0 && start + len <= line.length()); - wxString expr = line.Mid(start + 1, len - 2); - rpn.Set(expr.utf8_str()); - RPN_ERROR err = rpn.Parse(); - if (err == RPN_OK) { - RPNvalue val = rpn.Value(); - if (val.Alpha()) { - expr = wxString::FromUTF8(val.Text()); - } else { - expr = wxString::Format(wxT("%.4f"), val.Double()); - StripTrailingZeros(&expr); - } - } else if (err == RPN_EMPTY) { - /* this means that the expression ended with an assignment */ - expr = wxEmptyString; - } else { - wxString msg = wxString::Format(wxT("RPN expression error \"%s\" on line %u, expression \"%s\""), - rpn_errors[err], tidx + 1, expr.c_str()); - wxMessageBox(msg); - expr = wxEmptyString; - errorcount++; - } - str_replace(line, start, len, expr); - } - line.Trim(); - if (line.length() > 0) - symbol->Add(line); - tidx++; - } - if (endlabel.length() > 0) { - wxMessageBox(wxString::Format(wxT("RPN expression error: no match for label \"%s\""), endlabel.c_str())); - errorcount++; - } - - return errorcount == 0; + return errorcount == 0; } /* For symbols and footprints; also checkes whether the template exists */ wxString GetTemplateName(const wxArrayString& module) { - bool symbolmode = false; - wxString name = wxEmptyString; - for (unsigned idx = 0; name.length() == 0 && idx < module.Count(); idx++) { - wxString line = module[idx]; - wxString keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("AR")) == 0 || keyword.Cmp(wxT("#template")) == 0) { - name = line; - } else if (keyword.CmpNoCase(wxT("F4")) == 0) { - name = GetToken(&line); - symbolmode = true; - } - } - - /* strip off parameters */ - if (name.Find(wxT('[')) > 0) { - //??? wxString parameters = name.AfterFirst(wxT('[')).BeforeLast(wxT(']')); - name = name.BeforeFirst(wxT('[')); - } - - wxString ext = symbolmode ? wxT(".st") : wxT(".mt"); - wxString path = theApp->GetTemplatePath() + wxT(DIRSEP_STR) + name + ext; - if (!wxFileExists(path)) - return wxEmptyString; - - return name; + bool symbolmode = false; + wxString name = wxEmptyString; + for (unsigned idx = 0; name.length() == 0 && idx < module.Count(); idx++) { + wxString line = module[idx]; + wxString keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("AR")) == 0 || keyword.Cmp(wxT("#template")) == 0) { + name = line; + } else if (keyword.CmpNoCase(wxT("F4")) == 0) { + name = GetToken(&line); + symbolmode = true; + } + } + + /* strip off parameters */ + if (name.Find(wxT('[')) > 0) { + //??? wxString parameters = name.AfterFirst(wxT('[')).BeforeLast(wxT(']')); + name = name.BeforeFirst(wxT('[')); + } + + wxString ext = symbolmode ? wxT(".st") : wxT(".mt"); + wxString path = theApp->GetTemplatePath() + wxT(DIRSEP_STR) + name + ext; + if (!wxFileExists(path)) + return wxEmptyString; + + return name; } /* For symbols and footprints */ wxString GetDescription(const wxArrayString& module, bool symbolmode) { - /* although it is possible to detect whether the "module" contains a footprint - or a symbol, it is probably best not to try */ - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - wxString keyword = GetToken(&line); - if (!symbolmode && keyword.CmpNoCase(wxT("Cd")) == 0) { - return line; - } else if (!symbolmode && keyword.Cmp(wxT("(descr")) == 0) { - line = line.Left(line.length() - 1); /* strip trailing quote */ - return GetToken(&line); /* to strip the double quotes (if present) */ - } else if (symbolmode && keyword.CmpNoCase(wxT("D")) == 0) { - return line; - } - } - return wxEmptyString; + /* although it is possible to detect whether the "module" contains a footprint + or a symbol, it is probably best not to try */ + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + wxString keyword = GetToken(&line); + if (!symbolmode && keyword.CmpNoCase(wxT("Cd")) == 0) { + return line; + } else if (!symbolmode && keyword.Cmp(wxT("(descr")) == 0) { + line = line.Left(line.length() - 1); /* strip trailing quote */ + return GetToken(&line); /* to strip the double quotes (if present) */ + } else if (symbolmode && keyword.CmpNoCase(wxT("D")) == 0) { + return line; + } + } + return wxEmptyString; } /* For symbols and footprints */ bool SetDescription(wxArrayString& module, const wxString& description, bool symbolmode) { - /* although it is possible to detect whether the "module" contains a footprint - or a symbol, it is probably best not to try */ - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - wxString keyword = GetToken(&line); - if (!symbolmode && keyword.CmpNoCase(wxT("Cd")) == 0) { - if (description.length() == 0) - module.RemoveAt(idx); - else - module[idx] = wxT("Cd ") + description; - return true; - } else if (!symbolmode && keyword.Cmp(wxT("(descr")) == 0) { - module[idx] = wxT("(descr \"") + description + wxT("\")"); - return true; - } else if (symbolmode && keyword.CmpNoCase(wxT("D")) == 0) { - if (description.length() == 0) - module.RemoveAt(idx); - else - module[idx] = wxT("D ") + description; - return true; - } - } - /* if a component did not already have a description, one should be inserted */ - if (symbolmode) { - wxString name = wxEmptyString; - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - wxString keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("$CMP")) == 0) { - module.Insert(wxT("D ") + description, idx + 1); - return true; - } else if (keyword.CmpNoCase(wxT("DEF")) == 0) { - name = GetToken(&line); - } - } - /* if arrived here, the symbol does not have any documentation or keywords - yet, so create the complete section */ - wxASSERT(name.length() > 0); /* if the name is not set, this is not a valid symbol record */ - module.Add(wxT("#")); - module.Add(wxT("$CMP ") + name); - module.Add(wxT("D ") + description); - module.Add(wxT("$ENDCMP")); - } else { - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - wxString keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("$MODULE")) == 0) { - module.Insert(wxT("Cd ") + description, idx + 1); - return true; - } else if (keyword.Cmp(wxT("(module")) == 0) { - module.Insert(wxT("(descr \"") + description + wxT("\")"), idx + 1); - return true; - } - } - } - return false; + /* although it is possible to detect whether the "module" contains a footprint + or a symbol, it is probably best not to try */ + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + wxString keyword = GetToken(&line); + if (!symbolmode && keyword.CmpNoCase(wxT("Cd")) == 0) { + if (description.length() == 0) + module.RemoveAt(idx); + else + module[idx] = wxT("Cd ") + description; + return true; + } else if (!symbolmode && keyword.Cmp(wxT("(descr")) == 0) { + module[idx] = wxT("(descr \"") + description + wxT("\")"); + return true; + } else if (symbolmode && keyword.CmpNoCase(wxT("D")) == 0) { + if (description.length() == 0) + module.RemoveAt(idx); + else + module[idx] = wxT("D ") + description; + return true; + } + } + /* if a component did not already have a description, one should be inserted */ + if (symbolmode) { + wxString name = wxEmptyString; + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + wxString keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("$CMP")) == 0) { + module.Insert(wxT("D ") + description, idx + 1); + return true; + } else if (keyword.CmpNoCase(wxT("DEF")) == 0) { + name = GetToken(&line); + } + } + /* if arrived here, the symbol does not have any documentation or keywords + yet, so create the complete section */ + wxASSERT(name.length() > 0); /* if the name is not set, this is not a valid symbol record */ + module.Add(wxT("#")); + module.Add(wxT("$CMP ") + name); + module.Add(wxT("D ") + description); + module.Add(wxT("$ENDCMP")); + } else { + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + wxString keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("$MODULE")) == 0) { + module.Insert(wxT("Cd ") + description, idx + 1); + return true; + } else if (keyword.Cmp(wxT("(module")) == 0) { + module.Insert(wxT("(descr \"") + description + wxT("\")"), idx + 1); + return true; + } + } + } + return false; } /* For symbols and footprints */ wxString GetKeywords(const wxArrayString& module, bool symbolmode) { - /* although it is possible to detect whether the "module" contains a footprint - or a symbol, it is probably best not to try */ - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - wxString keyword = GetToken(&line); - if (!symbolmode && keyword.CmpNoCase(wxT("Kw")) == 0) { - return line; - } else if (!symbolmode && keyword.Cmp(wxT("(tags")) == 0) { - line = line.Left(line.length() - 1); /* strip trailing quote */ - return GetToken(&line); /* to strip the double quotes (if present) */ - } else if (symbolmode && keyword.CmpNoCase(wxT("K")) == 0) { - return line; - } - } - return wxEmptyString; + /* although it is possible to detect whether the "module" contains a footprint + or a symbol, it is probably best not to try */ + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + wxString keyword = GetToken(&line); + if (!symbolmode && keyword.CmpNoCase(wxT("Kw")) == 0) { + return line; + } else if (!symbolmode && keyword.Cmp(wxT("(tags")) == 0) { + line = line.Left(line.length() - 1); /* strip trailing quote */ + return GetToken(&line); /* to strip the double quotes (if present) */ + } else if (symbolmode && keyword.CmpNoCase(wxT("K")) == 0) { + return line; + } + } + return wxEmptyString; } /* For symbols and footprints */ bool SetKeywords(wxArrayString& module, const wxString& keywords, bool symbolmode) { - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - wxString keyword = GetToken(&line); - if (!symbolmode && keyword.CmpNoCase(wxT("Kw")) == 0) { - module[idx] = wxT("Kw ") + keywords; - return true; - } else if (!symbolmode && keyword.Cmp(wxT("(tags")) == 0) { + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + wxString keyword = GetToken(&line); + if (!symbolmode && keyword.CmpNoCase(wxT("Kw")) == 0) { + module[idx] = wxT("Kw ") + keywords; + return true; + } else if (!symbolmode && keyword.Cmp(wxT("(tags")) == 0) { module[idx] = wxT("(tags \"") + keywords + wxT("\")"); - return true; - } else if (symbolmode && keyword.CmpNoCase(wxT("K")) == 0) { - if (keywords.length() == 0) - module.RemoveAt(idx); - else - module[idx] = wxT("K ") + keywords; - return true; - } - } - /* if a symbol did not already have aliases, they should be inserted */ - if (keywords.length() == 0) - return true; /* nothing to insert */ - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - wxString keyword = GetToken(&line); - if (!symbolmode && keyword.CmpNoCase(wxT("$MODULE")) == 0) { - module.Insert(wxT("Kw ") + keywords, idx + 1); - return true; - } else if (!symbolmode && keyword.Cmp(wxT("(module")) == 0) { - module.Insert(wxT("(tags \"") + keywords + wxT("\")"), idx + 1); - return true; + return true; + } else if (symbolmode && keyword.CmpNoCase(wxT("K")) == 0) { + if (keywords.length() == 0) + module.RemoveAt(idx); + else + module[idx] = wxT("K ") + keywords; + return true; + } + } + /* if a symbol did not already have aliases, they should be inserted */ + if (keywords.length() == 0) + return true; /* nothing to insert */ + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + wxString keyword = GetToken(&line); + if (!symbolmode && keyword.CmpNoCase(wxT("$MODULE")) == 0) { + module.Insert(wxT("Kw ") + keywords, idx + 1); + return true; + } else if (!symbolmode && keyword.Cmp(wxT("(module")) == 0) { + module.Insert(wxT("(tags \"") + keywords + wxT("\")"), idx + 1); + return true; } else if (symbolmode && keyword.CmpNoCase(wxT("$ENDCMP")) == 0) { - module.Insert(wxT("K ") + keywords, idx); - return true; - } - } - return false; + module.Insert(wxT("K ") + keywords, idx); + return true; + } + } + return false; } /* For symbols */ wxString GetPrefix(const wxArrayString& symbol) { - for (unsigned idx = 0; idx < symbol.Count(); idx++) { - wxString line = symbol[idx]; - wxString keyword = GetToken(&line); - if (keyword.Cmp(wxT("DEF")) == 0) { - GetToken(&line); - keyword = GetToken(&line); - return keyword; - } - } - return wxEmptyString; + for (unsigned idx = 0; idx < symbol.Count(); idx++) { + wxString line = symbol[idx]; + wxString keyword = GetToken(&line); + if (keyword.Cmp(wxT("DEF")) == 0) { + GetToken(&line); + keyword = GetToken(&line); + return keyword; + } + } + return wxEmptyString; } /* For symbols */ wxString GetAliases(const wxArrayString& symbol) { - for (unsigned idx = 0; idx < symbol.Count(); idx++) { - wxString line = symbol[idx]; - wxString keyword = GetToken(&line); - if (keyword.Cmp(wxT("ALIAS")) == 0) - return line; - } - return wxEmptyString; + for (unsigned idx = 0; idx < symbol.Count(); idx++) { + wxString line = symbol[idx]; + wxString keyword = GetToken(&line); + if (keyword.Cmp(wxT("ALIAS")) == 0) + return line; + } + return wxEmptyString; } /* For symbols */ bool SetAliases(wxArrayString& module, const wxString& aliases) { - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - wxString keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("ALIAS")) == 0) { - if (aliases.length() == 0) - module.RemoveAt(idx); - else - module[idx] = wxT("ALIAS ") + aliases; - return true; - } - } - /* if a symbol did not already have aliases, they should be inserted */ - if (aliases.length() == 0) - return true; /* nothing to insert */ - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - wxString keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("DEF")) == 0) { - module.Insert(wxT("ALIAS ") + aliases, idx + 1); - return true; - } - } - return false; + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + wxString keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("ALIAS")) == 0) { + if (aliases.length() == 0) + module.RemoveAt(idx); + else + module[idx] = wxT("ALIAS ") + aliases; + return true; + } + } + /* if a symbol did not already have aliases, they should be inserted */ + if (aliases.length() == 0) + return true; /* nothing to insert */ + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + wxString keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("DEF")) == 0) { + module.Insert(wxT("ALIAS ") + aliases, idx + 1); + return true; + } + } + return false; } /* For symbols */ wxString GetFootprints(const wxArrayString& module) { - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - if (line.CmpNoCase(wxT("$FPLIST")) == 0) { - wxString total = wxEmptyString; - while (++idx < module.Count()) { - wxString line = module[idx]; - if (line.CmpNoCase(wxT("$ENDFPLIST")) == 0) - break; - if (total.length() > 0) - total += wxT(" "); - total += line; - } - return total; - } - } - return wxEmptyString; + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + if (line.CmpNoCase(wxT("$FPLIST")) == 0) { + wxString total = wxEmptyString; + while (++idx < module.Count()) { + wxString line = module[idx]; + if (line.CmpNoCase(wxT("$ENDFPLIST")) == 0) + break; + if (total.length() > 0) + total += wxT(" "); + total += line; + } + return total; + } + } + return wxEmptyString; } /* For symbols */ bool SetFootprints(wxArrayString& module, const wxString& footprints) { - unsigned pos = 0; - /* find the section, erase it completely */ - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - if (line.CmpNoCase(wxT("$FPLIST")) == 0) { - pos = idx; /* keep the insertion position */ - do { - line = module[pos]; - module.RemoveAt(pos); - } while (pos < module.Count() && line.CmpNoCase(wxT("$ENDFPLIST")) != 0); - } - } - if (footprints.length() == 0) - return true; /* no new footprints to insert */ - - /* no footprint filter was found, insert it near the top */ - if (pos == 0) { - for (unsigned idx = 0; pos == 0 && idx < module.Count(); idx++) { - wxString line = module[idx]; - wxString keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("DEF")) == 0) - pos = idx + 1; - } - } - - /* create a new section */ - wxString list = footprints; - list.Trim(); - list.Trim(false); - if (list.length() > 0) { - module.Insert(wxT("$FPLIST"), pos++); - while (list.length() > 0) { - wxString pattern = GetToken(&list); - module.Insert(pattern, pos++); - } - module.Insert(wxT("$ENDFPLIST"), pos); - } - - return true; + unsigned pos = 0; + /* find the section, erase it completely */ + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + if (line.CmpNoCase(wxT("$FPLIST")) == 0) { + pos = idx; /* keep the insertion position */ + do { + line = module[pos]; + module.RemoveAt(pos); + } while (pos < module.Count() && line.CmpNoCase(wxT("$ENDFPLIST")) != 0); + } + } + if (footprints.length() == 0) + return true; /* no new footprints to insert */ + + /* no footprint filter was found, insert it near the top */ + if (pos == 0) { + for (unsigned idx = 0; pos == 0 && idx < module.Count(); idx++) { + wxString line = module[idx]; + wxString keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("DEF")) == 0) + pos = idx + 1; + } + } + + /* create a new section */ + wxString list = footprints; + list.Trim(); + list.Trim(false); + if (list.length() > 0) { + module.Insert(wxT("$FPLIST"), pos++); + while (list.length() > 0) { + wxString pattern = GetToken(&list); + module.Insert(pattern, pos++); + } + module.Insert(wxT("$ENDFPLIST"), pos); + } + + return true; } /** GetPinNames() retrieves the names and numbers of the pins in an array. - * \param module the symbol data structure - * \param info if not NULL, the extracted information is stored here - * \param count if not NULL, the total count of pins is stored here + * \param module the symbol data structure + * \param info if not NULL, the extracted information is stored here + * \param count if not NULL, the total count of pins is stored here * * \note "info" must be allocated with sufficient size; to query how many - * blocks to allocate, set "info" to NULL and "count" to a variable - * (non-NULL). + * blocks to allocate, set "info" to NULL and "count" to a variable + * (non-NULL). * * For symbols. */ bool GetPinNames(const wxArrayString& module, PinInfo* info, int* count) { - int pinidx = 0; - bool indraw = false; - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - if (indraw) { - wxString keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("ENDDRAW")) == 0) { - indraw = false; - break; - } if (keyword.CmpNoCase(wxT("X")) == 0) { - wxString name = GetToken(&line); - wxString number = GetToken(&line); - double x = GetTokenLong(&line) * 0.0254; - double y = GetTokenLong(&line) * 0.0254; - GetToken(&line); /* ignore length */ - wxString orient = GetToken(&line); - GetToken(&line); /* ignore text and pin number size */ - GetToken(&line); - long part = GetTokenLong(&line); - if (GetTokenLong(&line) > 1) - continue; /* ignore De Morgan converted shape */ - wxString type = GetToken(&line); - wxString shape = GetToken(&line); - /* add the name the the description to the output array */ - if (info != NULL) { - info[pinidx].seq = pinidx; - info[pinidx].number = number; - info[pinidx].name = name; + int pinidx = 0; + bool indraw = false; + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + if (indraw) { + wxString keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("ENDDRAW")) == 0) { + indraw = false; + break; + } if (keyword.CmpNoCase(wxT("X")) == 0) { + wxString name = GetToken(&line); + wxString number = GetToken(&line); + double x = GetTokenLong(&line) * 0.0254; + double y = GetTokenLong(&line) * 0.0254; + GetToken(&line); /* ignore length */ + wxString orient = GetToken(&line); + GetToken(&line); /* ignore text and pin number size */ + GetToken(&line); + long part = GetTokenLong(&line); + if (GetTokenLong(&line) > 1) + continue; /* ignore De Morgan converted shape */ + wxString type = GetToken(&line); + wxString shape = GetToken(&line); + /* add the name the the description to the output array */ + if (info != NULL) { + info[pinidx].seq = pinidx; + info[pinidx].number = number; + info[pinidx].name = name; info[pinidx].part = part; - info[pinidx].x = x; - info[pinidx].y = y; - switch ((int)orient[0]) { - case 'R': - info[pinidx].section = PinInfo::Left; - break; - case 'L': - info[pinidx].section = PinInfo::Right; - break; - case 'D': - info[pinidx].section = PinInfo::Top; - break; - case 'U': - info[pinidx].section = PinInfo::Bottom; - break; - } - switch ((int)type[0]) { - case 'I': - info[pinidx].type = PinInfo::Input; - break; - case 'O': - info[pinidx].type = PinInfo::Output; - break; - case 'B': - info[pinidx].type = PinInfo::BiDir; - break; - case 'T': - info[pinidx].type = PinInfo::Tristate; - break; - case 'P': - info[pinidx].type = PinInfo::Passive; - break; - case 'C': - info[pinidx].type = PinInfo::OpenCol; - break; - case 'E': - info[pinidx].type = PinInfo::OpenEmit; - break; - case 'N': - info[pinidx].type = PinInfo::NC; - break; - case 'U': - info[pinidx].type = PinInfo::Unspecified; - break; - case 'W': - info[pinidx].type = PinInfo::PowerIn; - break; - case 'w': - info[pinidx].type = PinInfo::PowerOut; - break; - } - info[pinidx].shape = PinInfo::Other; - if (shape.length() == 0) - info[pinidx].shape = PinInfo::Line; - else if (shape.CmpNoCase(wxT("I")) == 0) - info[pinidx].shape = PinInfo::Inverted; - else if (shape.CmpNoCase(wxT("C")) == 0) - info[pinidx].shape = PinInfo::Clock; - else if (shape.CmpNoCase(wxT("CI")) == 0) - info[pinidx].shape = PinInfo::InvClock; - } - pinidx += 1; - } - } else if (line.CmpNoCase(wxT("DRAW")) == 0) { - indraw = true; - } - } - if (count != NULL) - *count = pinidx; - - if (info != NULL) { - /* sort the array on pin numbers (simple insertion sort) */ - for (int i = 1; i < pinidx; i++) { - PinInfo t = info[i]; - /* check whether the pin number of "t" is a number (it usually is) */ - long tn; - if (!t.number.ToLong(&tn)) - tn = LONG_MIN; - int j = i; - while (j > 0) { - /* check whether the value compared to is a number (it usually is) */ - int result; - long vn; - if (tn != LONG_MIN && info[j - 1].number.ToLong(&vn)) - result = tn - vn; - else - result = t.number.CmpNoCase(info[j - 1].number); - if (result >= 0) - break; - info[j] = info[j - 1]; - j--; - } - info[j] = t; - } + info[pinidx].x = x; + info[pinidx].y = y; + switch ((int)orient[0]) { + case 'R': + info[pinidx].section = PinInfo::Left; + break; + case 'L': + info[pinidx].section = PinInfo::Right; + break; + case 'D': + info[pinidx].section = PinInfo::Top; + break; + case 'U': + info[pinidx].section = PinInfo::Bottom; + break; + } + switch ((int)type[0]) { + case 'I': + info[pinidx].type = PinInfo::Input; + break; + case 'O': + info[pinidx].type = PinInfo::Output; + break; + case 'B': + info[pinidx].type = PinInfo::BiDir; + break; + case 'T': + info[pinidx].type = PinInfo::Tristate; + break; + case 'P': + info[pinidx].type = PinInfo::Passive; + break; + case 'C': + info[pinidx].type = PinInfo::OpenCol; + break; + case 'E': + info[pinidx].type = PinInfo::OpenEmit; + break; + case 'N': + info[pinidx].type = PinInfo::NC; + break; + case 'U': + info[pinidx].type = PinInfo::Unspecified; + break; + case 'W': + info[pinidx].type = PinInfo::PowerIn; + break; + case 'w': + info[pinidx].type = PinInfo::PowerOut; + break; + } + info[pinidx].shape = PinInfo::Other; + if (shape.length() == 0) + info[pinidx].shape = PinInfo::Line; + else if (shape.CmpNoCase(wxT("I")) == 0) + info[pinidx].shape = PinInfo::Inverted; + else if (shape.CmpNoCase(wxT("C")) == 0) + info[pinidx].shape = PinInfo::Clock; + else if (shape.CmpNoCase(wxT("CI")) == 0) + info[pinidx].shape = PinInfo::InvClock; + } + pinidx += 1; + } + } else if (line.CmpNoCase(wxT("DRAW")) == 0) { + indraw = true; + } + } + if (count != NULL) + *count = pinidx; + + if (info != NULL) { + /* sort the array on pin numbers (simple insertion sort) */ + for (int i = 1; i < pinidx; i++) { + PinInfo t = info[i]; + /* check whether the pin number of "t" is a number (it usually is) */ + long tn; + if (!t.number.ToLong(&tn)) + tn = LONG_MIN; + int j = i; + while (j > 0) { + /* check whether the value compared to is a number (it usually is) */ + int result; + long vn; + if (tn != LONG_MIN && info[j - 1].number.ToLong(&vn)) + result = tn - vn; + else + result = t.number.CmpNoCase(info[j - 1].number); + if (result >= 0) + break; + info[j] = info[j - 1]; + j--; + } + info[j] = t; + } /* if all pins are of part 1 (or general), there is only a single part */ bool pin1found = false; bool pin2found = false; - for (int i = 0; i < pinidx; i++) { + for (int i = 0; i < pinidx; i++) { if (info[i].part == 1) pin1found = true; if (info[i].part >= 2) pin2found = true; } if (pin1found && !pin2found) { - for (int i = 0; i < pinidx; i++) + for (int i = 0; i < pinidx; i++) info[i].part = 0; } - } + } - return true; + return true; } /** SetPinNames() can only adjust existing pins; it cannot add new pins, or @@ -4026,342 +4026,342 @@ bool GetPinNames(const wxArrayString& module, PinInfo* info, int* count) */ bool SetPinNames(wxArrayString& module, const PinInfo* info, int count) { - static const char type[] = { 'I', 'O', 'B', 'T', 'P', 'C', 'E', 'N', 'U', 'W', 'w' }; - static const char orientation[] = { 'R', 'L', 'D', 'U' }; - static const wxString shape[] = { wxT(""), wxT("I"), wxT("C"), wxT("CI"), wxEmptyString }; - - wxASSERT(info != NULL); - int sequence = 0; - bool indraw = false; - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - if (indraw) { - wxString keyword = GetToken(&line); - if (keyword.CmpNoCase(wxT("ENDDRAW")) == 0) { - indraw = false; - break; - } if (keyword.CmpNoCase(wxT("X")) == 0) { - /* first look through the pin definition whether this pin must be handled */ - GetToken(&line); /* ignore the pin name */ - GetToken(&line); /* ignore the pin number */ - long xpos = GetTokenLong(&line); /* save position and length */ - long ypos = GetTokenLong(&line); - long len = GetTokenLong(&line); - GetToken(&line); /* ignore orientation */ - long sznum = GetTokenLong(&line); /* save pin label sizes */ - long szname = GetTokenLong(&line); - long part = GetTokenLong(&line); /* save part */ - long dmg = GetTokenLong(&line); - if (dmg > 1) - continue; /* ignore De Morgan converted shape */ - GetToken(&line); /* ignore type */ - wxString curshape = GetToken(&line); - /* find the index for the sequence number */ - int pinidx; - for (pinidx = 0; pinidx < count && info[pinidx].seq != sequence; pinidx++) - /* nothing */; - wxASSERT(pinidx < count); /* sequence number should be found */ - sequence++; /* next time, search for the sequentially next pin */ - /* create the new line */ - wxString name = info[pinidx].name; - if (name.length() == 0) - name = wxT("~"); - if (info[pinidx].shape != PinInfo::Other) - curshape = shape[info[pinidx].shape]; + static const char type[] = { 'I', 'O', 'B', 'T', 'P', 'C', 'E', 'N', 'U', 'W', 'w' }; + static const char orientation[] = { 'R', 'L', 'D', 'U' }; + static const wxString shape[] = { wxT(""), wxT("I"), wxT("C"), wxT("CI"), wxEmptyString }; + + wxASSERT(info != NULL); + int sequence = 0; + bool indraw = false; + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + if (indraw) { + wxString keyword = GetToken(&line); + if (keyword.CmpNoCase(wxT("ENDDRAW")) == 0) { + indraw = false; + break; + } if (keyword.CmpNoCase(wxT("X")) == 0) { + /* first look through the pin definition whether this pin must be handled */ + GetToken(&line); /* ignore the pin name */ + GetToken(&line); /* ignore the pin number */ + long xpos = GetTokenLong(&line); /* save position and length */ + long ypos = GetTokenLong(&line); + long len = GetTokenLong(&line); + GetToken(&line); /* ignore orientation */ + long sznum = GetTokenLong(&line); /* save pin label sizes */ + long szname = GetTokenLong(&line); + long part = GetTokenLong(&line); /* save part */ + long dmg = GetTokenLong(&line); + if (dmg > 1) + continue; /* ignore De Morgan converted shape */ + GetToken(&line); /* ignore type */ + wxString curshape = GetToken(&line); + /* find the index for the sequence number */ + int pinidx; + for (pinidx = 0; pinidx < count && info[pinidx].seq != sequence; pinidx++) + /* nothing */; + wxASSERT(pinidx < count); /* sequence number should be found */ + sequence++; /* next time, search for the sequentially next pin */ + /* create the new line */ + wxString name = info[pinidx].name; + if (name.length() == 0) + name = wxT("~"); + if (info[pinidx].shape != PinInfo::Other) + curshape = shape[info[pinidx].shape]; else curshape = wxT(""); if (info[pinidx].type == PinInfo::NC) curshape = wxT("N") + curshape; - int section = info[pinidx].section; - if (section >= PinInfo::LeftCustom) - section -= PinInfo::LeftCustom; - line = wxString::Format(wxT("X %s %s %ld %ld %ld %c %ld %ld %ld %ld %c %s"), - name.c_str(), info[pinidx].number.c_str(), - xpos, ypos, len, orientation[section], - sznum, szname, part, dmg, - type[info[pinidx].type], curshape.c_str()); - line.Trim(); - module[idx] = line; - } - } else if (line.CmpNoCase(wxT("DRAW")) == 0) { - indraw = true; - } - } - return true; + int section = info[pinidx].section; + if (section >= PinInfo::LeftCustom) + section -= PinInfo::LeftCustom; + line = wxString::Format(wxT("X %s %s %ld %ld %ld %c %ld %ld %ld %ld %c %s"), + name.c_str(), info[pinidx].number.c_str(), + xpos, ypos, len, orientation[section], + sznum, szname, part, dmg, + type[info[pinidx].type], curshape.c_str()); + line.Trim(); + module[idx] = line; + } + } else if (line.CmpNoCase(wxT("DRAW")) == 0) { + indraw = true; + } + } + return true; } /** ReAssignPins() changes the standard sections of pins to custom sections, if - * these pins fall into the range for the custom section. + * these pins fall into the range for the custom section. */ void ReAssignPins(PinInfo* info, int count, const BodyInfo& body, const PinSection custsections[], size_t maxsections) { - wxASSERT(info); - for (size_t s = 0; s < maxsections; s++) { - if (!custsections[s].IsValid()) - continue; - for (int p = 0; p < count; p++) { - if ((custsections[s].Section() == PinInfo::LeftCustom && info[p].section != PinInfo::Left) - || (custsections[s].Section() == PinInfo::RightCustom && info[p].section != PinInfo::Right)) - continue; - double rel = (double)info[p].y / body.BodyLength + 0.5; - double crit = custsections[s].Criterion(); - wxASSERT(crit < -EPSILON || crit > EPSILON); - if ((crit > EPSILON && rel <= crit) /* the "custom" section is in the bottom half & the pin is in the bottom half */ - || (crit < EPSILON && rel >= 1 - crit)) /* the "custom" section is in the top half & the pin is in the top half */ - info[p].section = custsections[s].Section(); - } - } + wxASSERT(info); + for (size_t s = 0; s < maxsections; s++) { + if (!custsections[s].IsValid()) + continue; + for (int p = 0; p < count; p++) { + if ((custsections[s].Section() == PinInfo::LeftCustom && info[p].section != PinInfo::Left) + || (custsections[s].Section() == PinInfo::RightCustom && info[p].section != PinInfo::Right)) + continue; + double rel = (double)info[p].y / body.BodyLength + 0.5; + double crit = custsections[s].Criterion(); + wxASSERT(crit < -EPSILON || crit > EPSILON); + if ((crit > EPSILON && rel <= crit) /* the "custom" section is in the bottom half & the pin is in the bottom half */ + || (crit < EPSILON && rel >= 1 - crit)) /* the "custom" section is in the top half & the pin is in the top half */ + info[p].section = custsections[s].Section(); + } + } } /* Retrieves the extents of the drawings, for footprints and symbols */ bool GetBodySize(const wxArrayString& module, BodyInfo* info, bool symbolmode, bool unit_mm) { - wxASSERT(info != 0); - info->Clear(); - - double x1 = 0, y1 = 0, x2 = 0, y2 = 0; - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - wxString token = GetToken(&line); - if (!symbolmode && token.CmpNoCase(wxT("DS")) == 0) { - double x = GetTokenDim(&line, unit_mm); - double y = GetTokenDim(&line, unit_mm); - if (x < x1) - x1 = x; - else if (x > x2) - x2 = x; - if (y < y1) - y1 = y; - else if (y > y2) - y2 = y; - x = GetTokenDim(&line, unit_mm); - y = GetTokenDim(&line, unit_mm); - if (x < x1) - x1 = x; - else if (x > x2) - x2 = x; - if (y < y1) - y1 = y; - else if (y > y2) - y2 = y; - } else if (!symbolmode && (token.CmpNoCase(wxT("DC")) == 0 || token.CmpNoCase(wxT("DA")) == 0)) { - double xc = GetTokenDim(&line, unit_mm); - double yc = GetTokenDim(&line, unit_mm); - double xp = GetTokenDim(&line, unit_mm); - double yp = GetTokenDim(&line, unit_mm); - double radius = sqrt((xp - xc) * (xp - xc) + (yp - yc) * (yp - yc)); - if (xc - radius < x1) - x1 = xc - radius; - if (xc + radius > x2) - x2 = xc + radius; - if (yc - radius < y1) - y1 = yc - radius; - if (yc + radius > y2) - y2 = yc + radius; - } else if (token.Cmp(wxT("(fp_line")) == 0) { - wxASSERT(!symbolmode); - double x=0, y=0; - wxString section = GetSection(line, wxT("start")); - if (section.length() > 0) { - x = GetTokenDim(§ion, true); - y = GetTokenDim(§ion, true); - if (x < x1) - x1 = x; - else if (x > x2) - x2 = x; - if (y < y1) - y1 = y; - else if (y > y2) - y2 = y; - } - section = GetSection(line, wxT("end")); - if (section.length() > 0) { - x = GetTokenDim(§ion, true); - y = GetTokenDim(§ion, true); - if (x < x1) - x1 = x; - else if (x > x2) - x2 = x; - if (y < y1) - y1 = y; - else if (y > y2) - y2 = y; - } - } else if (token.Cmp(wxT("(fp_circle")) == 0) { - wxASSERT(!symbolmode); - double xc=0, yc=0, xp=0, yp=0; - wxString section = GetSection(line, wxT("center")); - if (section.length() > 0) { - xc = GetTokenDim(§ion, true); - yc = GetTokenDim(§ion, true); - } - section = GetSection(line, wxT("end")); - if (section.length() > 0) { - xp = GetTokenDim(§ion, true); - yp = GetTokenDim(§ion, true); - } - double radius = sqrt((xp - xc) * (xp - xc) + (yp - yc) * (yp - yc)); - if (xc - radius < x1) - x1 = xc - radius; - if (xc + radius > x2) - x2 = xc + radius; - if (yc - radius < y1) - y1 = yc - radius; - if (yc + radius > y2) - y2 = yc + radius; - } else if (token.Cmp(wxT("(fp_arc")) == 0) { - wxASSERT(!symbolmode); - double xc=0, yc=0, xp=0, yp=0; - wxString section = GetSection(line, wxT("start")); - if (section.length() > 0) { - xc = GetTokenDim(§ion, true); - yc = GetTokenDim(§ion, true); - } - section = GetSection(line, wxT("end")); - if (section.length() > 0) { - xp = GetTokenDim(§ion, true); - yp = GetTokenDim(§ion, true); - } - double radius = sqrt((xp - xc) * (xp - xc) + (yp - yc) * (yp - yc)); - if (xc - radius < x1) - x1 = xc - radius; - if (xc + radius > x2) - x2 = xc + radius; - if (yc - radius < y1) - y1 = yc - radius; - if (yc + radius > y2) - y2 = yc + radius; - } else if (symbolmode && token.Cmp(wxT("C")) == 0) { - double xc = GetTokenLong(&line) * 0.0254; - double yc = GetTokenLong(&line) * 0.0254; - double radius = GetTokenLong(&line) * 0.0254; - if (xc - radius < x1) - x1 = xc - radius; - if (xc + radius > x2) - x2 = xc + radius; - if (yc - radius < y1) - y1 = yc - radius; - if (yc + radius > y2) - y2 = yc + radius; - } else if (symbolmode && token.Cmp(wxT("S")) == 0) { - double px1 = GetTokenLong(&line) * 0.0254; - double py1 = GetTokenLong(&line) * 0.0254; - double px2 = GetTokenLong(&line) * 0.0254; - double py2 = GetTokenLong(&line) * 0.0254; - if (px1 > px2) { - double t = px1; - px1 = px2; - px2 = t; - } - if (py1 > py2) { - double t = py1; - py1 = py2; - py2 = t; - } - if (px1 < x1) - x1 = px1; - if (px2 > x2) - x2 = px2; - if (py1 < y1) - y1 = py1; - if (py2 > y2) - y2 = py2; - } else if (symbolmode && token.Cmp(wxT("P")) == 0) { - long count = GetTokenLong(&line); - GetToken(&line); /* ignore part */ - GetToken(&line); /* ignore dmg */ - GetToken(&line); /* ignore pen */ - while (count-- > 0) { - double x = GetTokenLong(&line) * 0.0254; - double y = GetTokenLong(&line) * 0.0254; - if (x < x1) - x1 = x; - else if (x > x2) - x2 = x; - if (y < y1) - y1 = y; - if (y > y2) - y2 = y; - } - } - } - - info->BodyLength = y2 - y1; - info->BodyWidth = x2 - x1; - return true; + wxASSERT(info != 0); + info->Clear(); + + double x1 = 0, y1 = 0, x2 = 0, y2 = 0; + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + wxString token = GetToken(&line); + if (!symbolmode && token.CmpNoCase(wxT("DS")) == 0) { + double x = GetTokenDim(&line, unit_mm); + double y = GetTokenDim(&line, unit_mm); + if (x < x1) + x1 = x; + else if (x > x2) + x2 = x; + if (y < y1) + y1 = y; + else if (y > y2) + y2 = y; + x = GetTokenDim(&line, unit_mm); + y = GetTokenDim(&line, unit_mm); + if (x < x1) + x1 = x; + else if (x > x2) + x2 = x; + if (y < y1) + y1 = y; + else if (y > y2) + y2 = y; + } else if (!symbolmode && (token.CmpNoCase(wxT("DC")) == 0 || token.CmpNoCase(wxT("DA")) == 0)) { + double xc = GetTokenDim(&line, unit_mm); + double yc = GetTokenDim(&line, unit_mm); + double xp = GetTokenDim(&line, unit_mm); + double yp = GetTokenDim(&line, unit_mm); + double radius = sqrt((xp - xc) * (xp - xc) + (yp - yc) * (yp - yc)); + if (xc - radius < x1) + x1 = xc - radius; + if (xc + radius > x2) + x2 = xc + radius; + if (yc - radius < y1) + y1 = yc - radius; + if (yc + radius > y2) + y2 = yc + radius; + } else if (token.Cmp(wxT("(fp_line")) == 0) { + wxASSERT(!symbolmode); + double x=0, y=0; + wxString section = GetSection(line, wxT("start")); + if (section.length() > 0) { + x = GetTokenDim(§ion, true); + y = GetTokenDim(§ion, true); + if (x < x1) + x1 = x; + else if (x > x2) + x2 = x; + if (y < y1) + y1 = y; + else if (y > y2) + y2 = y; + } + section = GetSection(line, wxT("end")); + if (section.length() > 0) { + x = GetTokenDim(§ion, true); + y = GetTokenDim(§ion, true); + if (x < x1) + x1 = x; + else if (x > x2) + x2 = x; + if (y < y1) + y1 = y; + else if (y > y2) + y2 = y; + } + } else if (token.Cmp(wxT("(fp_circle")) == 0) { + wxASSERT(!symbolmode); + double xc=0, yc=0, xp=0, yp=0; + wxString section = GetSection(line, wxT("center")); + if (section.length() > 0) { + xc = GetTokenDim(§ion, true); + yc = GetTokenDim(§ion, true); + } + section = GetSection(line, wxT("end")); + if (section.length() > 0) { + xp = GetTokenDim(§ion, true); + yp = GetTokenDim(§ion, true); + } + double radius = sqrt((xp - xc) * (xp - xc) + (yp - yc) * (yp - yc)); + if (xc - radius < x1) + x1 = xc - radius; + if (xc + radius > x2) + x2 = xc + radius; + if (yc - radius < y1) + y1 = yc - radius; + if (yc + radius > y2) + y2 = yc + radius; + } else if (token.Cmp(wxT("(fp_arc")) == 0) { + wxASSERT(!symbolmode); + double xc=0, yc=0, xp=0, yp=0; + wxString section = GetSection(line, wxT("start")); + if (section.length() > 0) { + xc = GetTokenDim(§ion, true); + yc = GetTokenDim(§ion, true); + } + section = GetSection(line, wxT("end")); + if (section.length() > 0) { + xp = GetTokenDim(§ion, true); + yp = GetTokenDim(§ion, true); + } + double radius = sqrt((xp - xc) * (xp - xc) + (yp - yc) * (yp - yc)); + if (xc - radius < x1) + x1 = xc - radius; + if (xc + radius > x2) + x2 = xc + radius; + if (yc - radius < y1) + y1 = yc - radius; + if (yc + radius > y2) + y2 = yc + radius; + } else if (symbolmode && token.Cmp(wxT("C")) == 0) { + double xc = GetTokenLong(&line) * 0.0254; + double yc = GetTokenLong(&line) * 0.0254; + double radius = GetTokenLong(&line) * 0.0254; + if (xc - radius < x1) + x1 = xc - radius; + if (xc + radius > x2) + x2 = xc + radius; + if (yc - radius < y1) + y1 = yc - radius; + if (yc + radius > y2) + y2 = yc + radius; + } else if (symbolmode && token.Cmp(wxT("S")) == 0) { + double px1 = GetTokenLong(&line) * 0.0254; + double py1 = GetTokenLong(&line) * 0.0254; + double px2 = GetTokenLong(&line) * 0.0254; + double py2 = GetTokenLong(&line) * 0.0254; + if (px1 > px2) { + double t = px1; + px1 = px2; + px2 = t; + } + if (py1 > py2) { + double t = py1; + py1 = py2; + py2 = t; + } + if (px1 < x1) + x1 = px1; + if (px2 > x2) + x2 = px2; + if (py1 < y1) + y1 = py1; + if (py2 > y2) + y2 = py2; + } else if (symbolmode && token.Cmp(wxT("P")) == 0) { + long count = GetTokenLong(&line); + GetToken(&line); /* ignore part */ + GetToken(&line); /* ignore dmg */ + GetToken(&line); /* ignore pen */ + while (count-- > 0) { + double x = GetTokenLong(&line) * 0.0254; + double y = GetTokenLong(&line) * 0.0254; + if (x < x1) + x1 = x; + else if (x > x2) + x2 = x; + if (y < y1) + y1 = y; + if (y > y2) + y2 = y; + } + } + } + + info->BodyLength = y2 - y1; + info->BodyWidth = x2 - x1; + return true; } /* Retrieves the sizes of the reference and text labels, as well as whether they are visible, for symbols and footprints */ bool GetTextLabelSize(const wxArrayString& module, LabelInfo* info, bool symbolmode, bool unit_mm) { - wxASSERT(info != 0); - info->RefLabelSize = info->ValueLabelSize = 0; - info->RefLabelVisible = info->ValueLabelVisible = false; - - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - wxString token = GetToken(&line); - if (!symbolmode && token.length() == 2 && token[0] == wxT('T') && isdigit(token[1])) { - GetToken(&line); /* ignore x position */ - GetToken(&line); /* ignore y position */ - double xsize = GetTokenDim(&line, unit_mm); - double ysize = GetTokenDim(&line, unit_mm); - double size = (xsize + ysize) / 2; - GetToken(&line); /* ignore text rotation */ - GetToken(&line); /* ignore pen width */ - GetToken(&line); /* ignore mirror */ - wxString visible = GetToken(&line); - if (token[1] == wxT('0')) { - info->RefLabelSize = size; - info->RefLabelVisible = (visible[0] == wxT('V')); - } else if (token[1] == wxT('1')) { - info->ValueLabelSize = size; - info->ValueLabelVisible = (visible[0] == wxT('V')); - } - } else if (token.Cmp(wxT("(fp_text")) == 0) { - wxASSERT(!symbolmode); - double xsize = 0, ysize = 0; - wxString type = GetToken(&line); - bool ishidden = line.Find(wxT(" hide ")) > 0; - wxString section = GetSection(line, wxT("effects")); - if (section.length() > 0) { - section = GetSection(section, wxT("font")); - if (section.length() > 0) { - wxString subsection = GetSection(section, wxT("size")); - if (subsection.length() > 0) { - xsize = GetTokenDim(&subsection, true); - ysize = GetTokenDim(&subsection, true); - } - } - } - double size = (xsize + ysize) / 2; - if (type.Cmp(wxT("reference")) == 0) { - info->RefLabelSize = size; - info->RefLabelVisible = !ishidden; - } else if (type.Cmp(wxT("value")) == 0) { - info->ValueLabelSize = size; - info->ValueLabelVisible = !ishidden; - } - } else if (symbolmode && token.length() == 2 && token[0] == wxT('F') && isdigit(token[1])) { - GetToken(&line); /* ignore text */ - GetToken(&line); /* ignore x position */ - GetToken(&line); /* ignore y position */ - double size = GetTokenLong(&line) * 0.0254; - GetToken(&line); /* ignore horz./vert. orientation */ - wxString visflag = GetToken(&line); - bool ishidden = (visflag == wxT('I')); - if (token[1] == wxT('0')) { - info->RefLabelSize = size; - info->RefLabelVisible = !ishidden; - } else if (token[1] == wxT('1')) { - info->ValueLabelSize = size; - info->ValueLabelVisible = !ishidden; - } - } - } - - return true; + wxASSERT(info != 0); + info->RefLabelSize = info->ValueLabelSize = 0; + info->RefLabelVisible = info->ValueLabelVisible = false; + + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + wxString token = GetToken(&line); + if (!symbolmode && token.length() == 2 && token[0] == wxT('T') && isdigit(token[1])) { + GetToken(&line); /* ignore x position */ + GetToken(&line); /* ignore y position */ + double xsize = GetTokenDim(&line, unit_mm); + double ysize = GetTokenDim(&line, unit_mm); + double size = (xsize + ysize) / 2; + GetToken(&line); /* ignore text rotation */ + GetToken(&line); /* ignore pen width */ + GetToken(&line); /* ignore mirror */ + wxString visible = GetToken(&line); + if (token[1] == wxT('0')) { + info->RefLabelSize = size; + info->RefLabelVisible = (visible[0] == wxT('V')); + } else if (token[1] == wxT('1')) { + info->ValueLabelSize = size; + info->ValueLabelVisible = (visible[0] == wxT('V')); + } + } else if (token.Cmp(wxT("(fp_text")) == 0) { + wxASSERT(!symbolmode); + double xsize = 0, ysize = 0; + wxString type = GetToken(&line); + bool ishidden = line.Find(wxT(" hide ")) > 0; + wxString section = GetSection(line, wxT("effects")); + if (section.length() > 0) { + section = GetSection(section, wxT("font")); + if (section.length() > 0) { + wxString subsection = GetSection(section, wxT("size")); + if (subsection.length() > 0) { + xsize = GetTokenDim(&subsection, true); + ysize = GetTokenDim(&subsection, true); + } + } + } + double size = (xsize + ysize) / 2; + if (type.Cmp(wxT("reference")) == 0) { + info->RefLabelSize = size; + info->RefLabelVisible = !ishidden; + } else if (type.Cmp(wxT("value")) == 0) { + info->ValueLabelSize = size; + info->ValueLabelVisible = !ishidden; + } + } else if (symbolmode && token.length() == 2 && token[0] == wxT('F') && isdigit(token[1])) { + GetToken(&line); /* ignore text */ + GetToken(&line); /* ignore x position */ + GetToken(&line); /* ignore y position */ + double size = GetTokenLong(&line) * 0.0254; + GetToken(&line); /* ignore horz./vert. orientation */ + wxString visflag = GetToken(&line); + bool ishidden = (visflag == wxT('I')); + if (token[1] == wxT('0')) { + info->RefLabelSize = size; + info->RefLabelVisible = !ishidden; + } else if (token[1] == wxT('1')) { + info->ValueLabelSize = size; + info->ValueLabelVisible = !ishidden; + } + } + } + + return true; } /* Sets the sizes of the reference and text labels, as well as whether @@ -4369,147 +4369,147 @@ bool GetTextLabelSize(const wxArrayString& module, LabelInfo* info, bool symbolm Note that unit_mm is ignored when symbolmode is true */ void SetTextLabelSize(wxArrayString& module, const LabelInfo& info, bool symbolmode, bool unit_mm) { - for (unsigned idx = 0; idx < module.Count(); idx++) { - wxString line = module[idx]; - wxString token = GetToken(&line); - if (!symbolmode && token.length() == 2 && token[0] == wxT('T') && (token[1] == '0' || token[1] == '1')) { - double xpos = GetTokenDim(&line, unit_mm); - double ypos = GetTokenDim(&line, unit_mm); - double xsize = GetTokenDim(&line, unit_mm); - double ysize = GetTokenDim(&line, unit_mm); - long rot = GetTokenLong(&line); - double pen = GetTokenDim(&line, unit_mm); - wxString mirror = GetToken(&line); - GetToken(&line); /* ignore visible flag */ - /* get new size; calculate new pen based on new size (keeping the same weight) */ - double size = (token[1] == '0') ? info.RefLabelSize : info.ValueLabelSize; - bool visible = (token[1] == '0') ? info.RefLabelVisible : info.ValueLabelVisible; - double weight = pen / ((xsize + ysize) / 2); - pen = size * weight; - module[idx] = wxString::Format(wxT("%s %.4f %.4f %.2f %.2f %ld %.2f %s %s %s"), - token.c_str(), MM(xpos), MM(ypos), MM(size), MM(size), - rot, MM(pen), mirror.c_str(), visible ? wxT("V") : wxT("I"), - line.c_str()); - } else if (token.Cmp(wxT("(fp_text")) == 0) { - /* verify that it is only reference or value (not user) */ - wxString type = GetToken(&line); - if (type.Cmp(wxT("reference")) == 0 || type.Cmp(wxT("value")) == 0) { - double xsize = 0, ysize = 0, pen = 0; - wxString text = GetToken(&line); - wxString at = GetSection(line, wxT("at")); - wxString layer = GetSection(line, wxT("layer")); - wxString section = GetSection(line, wxT("effects")); - if (section.length() > 0) { - section = GetSection(section, wxT("font")); - if (section.length() > 0) { - wxString subsection = GetSection(section, wxT("size")); - if (subsection.length() > 0) { - xsize = GetTokenDim(&subsection, true); - ysize = GetTokenDim(&subsection, true); - } - subsection = GetSection(section, wxT("thickness")); - if (subsection.length() > 0) - pen = GetTokenDim(&subsection, true); - } - } - double weight = pen / ((xsize + ysize) / 2); - double size; - bool visible; - if (type.Cmp(wxT("reference")) == 0) { - size = info.RefLabelSize; - visible = info.RefLabelVisible; - } else { - wxASSERT(type.Cmp(wxT("value")) == 0); - size = info.ValueLabelSize; - visible = info.ValueLabelVisible; - } - line = wxT("(fp_text ") + type + wxT(" \"") + text + wxT("\""); - if (at.length() > 0) - line += wxT(" (at ") + at + wxT(")"); - if (layer.length() > 0) - line += wxT(" (layer ") + layer + wxT(")"); - if (!visible) - line += wxT(" hide"); - line += wxString::Format(wxT(" (effects (font (size %.4f %.4f) (thickness %.4f))))"), - size, size, size * weight); - module[idx] = line; - } - } else if (symbolmode && token.length() == 2 && token[0] == wxT('F') && (token[1] == '0' || token[1] == '1')) { - wxString text = GetToken(&line); - wxString xpos = GetToken(&line); - wxString ypos = GetToken(&line); - GetToken(&line); /* skip size */ - wxString orient = GetToken(&line); - GetToken(&line); /* skip visible/hidden */ - double size = (token[1] == '0') ? info.RefLabelSize : info.ValueLabelSize; - bool visible = (token[1] == '0') ? info.RefLabelVisible : info.ValueLabelVisible; - module[idx] = wxString::Format(wxT("%s \"%s\" %s %s %ld %s %c %s"), - token.c_str(), text.c_str(), xpos.c_str(), ypos.c_str(), - (long)(size / 0.0254 + 0.5), orient.c_str(), - (visible ? 'V' : 'I'), line.c_str()); - } - } + for (unsigned idx = 0; idx < module.Count(); idx++) { + wxString line = module[idx]; + wxString token = GetToken(&line); + if (!symbolmode && token.length() == 2 && token[0] == wxT('T') && (token[1] == '0' || token[1] == '1')) { + double xpos = GetTokenDim(&line, unit_mm); + double ypos = GetTokenDim(&line, unit_mm); + double xsize = GetTokenDim(&line, unit_mm); + double ysize = GetTokenDim(&line, unit_mm); + long rot = GetTokenLong(&line); + double pen = GetTokenDim(&line, unit_mm); + wxString mirror = GetToken(&line); + GetToken(&line); /* ignore visible flag */ + /* get new size; calculate new pen based on new size (keeping the same weight) */ + double size = (token[1] == '0') ? info.RefLabelSize : info.ValueLabelSize; + bool visible = (token[1] == '0') ? info.RefLabelVisible : info.ValueLabelVisible; + double weight = pen / ((xsize + ysize) / 2); + pen = size * weight; + module[idx] = wxString::Format(wxT("%s %.4f %.4f %.2f %.2f %ld %.2f %s %s %s"), + token.c_str(), MM(xpos), MM(ypos), MM(size), MM(size), + rot, MM(pen), mirror.c_str(), visible ? wxT("V") : wxT("I"), + line.c_str()); + } else if (token.Cmp(wxT("(fp_text")) == 0) { + /* verify that it is only reference or value (not user) */ + wxString type = GetToken(&line); + if (type.Cmp(wxT("reference")) == 0 || type.Cmp(wxT("value")) == 0) { + double xsize = 0, ysize = 0, pen = 0; + wxString text = GetToken(&line); + wxString at = GetSection(line, wxT("at")); + wxString layer = GetSection(line, wxT("layer")); + wxString section = GetSection(line, wxT("effects")); + if (section.length() > 0) { + section = GetSection(section, wxT("font")); + if (section.length() > 0) { + wxString subsection = GetSection(section, wxT("size")); + if (subsection.length() > 0) { + xsize = GetTokenDim(&subsection, true); + ysize = GetTokenDim(&subsection, true); + } + subsection = GetSection(section, wxT("thickness")); + if (subsection.length() > 0) + pen = GetTokenDim(&subsection, true); + } + } + double weight = pen / ((xsize + ysize) / 2); + double size; + bool visible; + if (type.Cmp(wxT("reference")) == 0) { + size = info.RefLabelSize; + visible = info.RefLabelVisible; + } else { + wxASSERT(type.Cmp(wxT("value")) == 0); + size = info.ValueLabelSize; + visible = info.ValueLabelVisible; + } + line = wxT("(fp_text ") + type + wxT(" \"") + text + wxT("\""); + if (at.length() > 0) + line += wxT(" (at ") + at + wxT(")"); + if (layer.length() > 0) + line += wxT(" (layer ") + layer + wxT(")"); + if (!visible) + line += wxT(" hide"); + line += wxString::Format(wxT(" (effects (font (size %.4f %.4f) (thickness %.4f))))"), + size, size, size * weight); + module[idx] = line; + } + } else if (symbolmode && token.length() == 2 && token[0] == wxT('F') && (token[1] == '0' || token[1] == '1')) { + wxString text = GetToken(&line); + wxString xpos = GetToken(&line); + wxString ypos = GetToken(&line); + GetToken(&line); /* skip size */ + wxString orient = GetToken(&line); + GetToken(&line); /* skip visible/hidden */ + double size = (token[1] == '0') ? info.RefLabelSize : info.ValueLabelSize; + bool visible = (token[1] == '0') ? info.RefLabelVisible : info.ValueLabelVisible; + module[idx] = wxString::Format(wxT("%s \"%s\" %s %s %ld %s %c %s"), + token.c_str(), text.c_str(), xpos.c_str(), ypos.c_str(), + (long)(size / 0.0254 + 0.5), orient.c_str(), + (visible ? 'V' : 'I'), line.c_str()); + } + } } bool TranslatePadInfo(wxArrayString* module, FootprintInfo* info) { - wxASSERT(module != 0); - wxASSERT(info != 0); - info->Clear(info->Type); /* clear fields (but set the type) */ - - /* first create an index of the start positions of each pad (count the number - of pads too); the index will speed up the operation of walking through the - pads, as the pads are not necessarily stored in the order of pin numbers */ - struct PadDim { - unsigned startidx; /* index in the module where the pad definitions starts (or 0 for an invalid pad) */ - double x, y; - double width, height; + wxASSERT(module != 0); + wxASSERT(info != 0); + info->Clear(info->Type); /* clear fields (but set the type) */ + + /* first create an index of the start positions of each pad (count the number + of pads too); the index will speed up the operation of walking through the + pads, as the pads are not necessarily stored in the order of pin numbers */ + struct PadDim { + unsigned startidx; /* index in the module where the pad definitions starts (or 0 for an invalid pad) */ + double x, y; + double width, height; double orgwidth, orgheight; /* pad width/height may change if multiple overlapping pads are combined */ - long angle; - char shape; - double drillwidth, drillheight; /* for round holes, only drillwidth is set */ - bool rotate; /* set to true if the pad must be rotated by 90 degrees relative to the anchor pad */ - } *padlist = NULL; - int padcount = 0; /* total number of pads considered */ + long angle; + char shape; + double drillwidth, drillheight; /* for round holes, only drillwidth is set */ + bool rotate; /* set to true if the pad must be rotated by 90 degrees relative to the anchor pad */ + } *padlist = NULL; + int padcount = 0; /* total number of pads considered */ int padvalid = 0; /* valid, numbered pads */ int padmech = 0; /* mechanical pads (no name, no number) */ - bool DryRun = false; - bool unit_mm = (info->Type >= VER_MM); - do { - DryRun = !DryRun; - if (!DryRun) { + bool DryRun = false; + bool unit_mm = (info->Type >= VER_MM); + do { + DryRun = !DryRun; + if (!DryRun) { padcount = (padvalid + 1) + padmech; /* padvalid holds the top pad number, so +1 to include it */ - padlist = new PadDim[padcount]; - wxASSERT(padlist != NULL); - for (int idx = 0; idx < padcount; idx++) - padlist[idx].startidx = 0; + padlist = new PadDim[padcount]; + wxASSERT(padlist != NULL); + for (int idx = 0; idx < padcount; idx++) + padlist[idx].startidx = 0; padmech = 0; - } - double padx = 0, pady = 0, padwidth = 0, padheight = 0; - double drillwidth = 0, drillheight = 0; - char padshape = '\0'; - long padangle = 0; - unsigned startidx = 0; - long pinnr = PIN_UNKNOWN; - for (unsigned idx = 0; idx < module->Count(); idx++) { - wxString line = module->Item(idx); - line.Trim(false); - if (line[0] == wxT('$')) { - if (line.CmpNoCase(wxT("$PAD")) == 0) { - startidx = idx; - } else if (line.CmpNoCase(wxT("$EndPAD")) == 0) { - if (DryRun) { - if (pinnr > padvalid) - padvalid = pinnr; + } + double padx = 0, pady = 0, padwidth = 0, padheight = 0; + double drillwidth = 0, drillheight = 0; + char padshape = '\0'; + long padangle = 0; + unsigned startidx = 0; + long pinnr = PIN_UNKNOWN; + for (unsigned idx = 0; idx < module->Count(); idx++) { + wxString line = module->Item(idx); + line.Trim(false); + if (line[0] == wxT('$')) { + if (line.CmpNoCase(wxT("$PAD")) == 0) { + startidx = idx; + } else if (line.CmpNoCase(wxT("$EndPAD")) == 0) { + if (DryRun) { + if (pinnr > padvalid) + padvalid = pinnr; else if (pinnr == PIN_ANOMYM) padmech++; /* this is redundant for overlapping anonymous pads that form an exposed pad, but it does not hurt either */ - } else if (pinnr != PIN_UNKNOWN) { - wxASSERT((pinnr > 0 && pinnr <= padvalid) || pinnr == PIN_ANOMYM); + } else if (pinnr != PIN_UNKNOWN) { + wxASSERT((pinnr > 0 && pinnr <= padvalid) || pinnr == PIN_ANOMYM); if (pinnr == PIN_ANOMYM) { - /* check whether this pad overlaps with the previous pad of the + /* check whether this pad overlaps with the previous pad of the same size, which is also an anonymous pad -> if so, these pads will be merged, so the count of "mechanical" pads must not be - increased and the count of total pads (based on the dry run) + increased and the count of total pads (based on the dry run) must be decreased */ int new_padmech = padmech + 1; /* preset to non-merged pad */ if (padmech > 0) { @@ -4523,10 +4523,11 @@ bool TranslatePadInfo(wxArrayString* module, FootprintInfo* info) new_padmech = padmech; /* reset mechanical pad count */ } } - } - pinnr = padvalid + new_padmech; + } + padmech = new_padmech; + pinnr = padvalid + padmech; } - wxASSERT(pinnr > 0 && pinnr < padcount); + wxASSERT(pinnr > 0 && pinnr < padcount); if (padlist[pinnr].startidx > 0) { /* pad with this number already exists, see whether to merge with it */ if (Equal(padlist[pinnr].orgwidth, padwidth) && Equal(padlist[pinnr].orgheight, padheight)) { @@ -4535,616 +4536,616 @@ bool TranslatePadInfo(wxArrayString* module, FootprintInfo* info) slice.SetMid(padx, pady, padwidth, padheight); if (pad.OverlapOrTouch(slice)) { pad.Union(slice); - padlist[pinnr].x = pad.GetMidX(); - padlist[pinnr].y = pad.GetMidY(); - padlist[pinnr].width = pad.GetWidth(); - padlist[pinnr].height = pad.GetHeight(); + padlist[pinnr].x = pad.GetMidX(); + padlist[pinnr].y = pad.GetMidY(); + padlist[pinnr].width = pad.GetWidth(); + padlist[pinnr].height = pad.GetHeight(); } } } else { - padlist[pinnr].startidx = startidx; - padlist[pinnr].x = padx; - padlist[pinnr].y = pady; - padlist[pinnr].width = padwidth; - padlist[pinnr].height = padheight; - padlist[pinnr].angle = padangle; - padlist[pinnr].shape = padshape; - padlist[pinnr].drillwidth = drillwidth; - padlist[pinnr].drillheight = drillheight; - padlist[pinnr].orgwidth = padwidth; - padlist[pinnr].orgheight = padheight; + padlist[pinnr].startidx = startidx; + padlist[pinnr].x = padx; + padlist[pinnr].y = pady; + padlist[pinnr].width = padwidth; + padlist[pinnr].height = padheight; + padlist[pinnr].angle = padangle; + padlist[pinnr].shape = padshape; + padlist[pinnr].drillwidth = drillwidth; + padlist[pinnr].drillheight = drillheight; + padlist[pinnr].orgwidth = padwidth; + padlist[pinnr].orgheight = padheight; } - } - padx = pady = padwidth = padheight = 0; - padangle = 0; - drillwidth = drillheight = 0; - padshape = '\0'; - startidx = 0; - pinnr = PIN_UNKNOWN; - } - continue; - } else if (line[0] == wxT('(') && line.Left(4).Cmp(wxT("(pad")) == 0) { - GetToken(&line); /* ignore "(pad" */ - wxString pin = GetToken(&line); - pinnr = GetPadNumber(pin, &info->MtxWidth, &info->MtxHeight); - if (pinnr <= 0 && pinnr != PIN_ANOMYM) - pinnr = PIN_UNKNOWN; - if (DryRun) { - if (pinnr > padvalid) - padvalid = pinnr; + } + padx = pady = padwidth = padheight = 0; + padangle = 0; + drillwidth = drillheight = 0; + padshape = '\0'; + startidx = 0; + pinnr = PIN_UNKNOWN; + } + continue; + } else if (line[0] == wxT('(') && line.Left(4).Cmp(wxT("(pad")) == 0) { + GetToken(&line); /* ignore "(pad" */ + wxString pin = GetToken(&line); + pinnr = GetPadNumber(pin, &info->MtxWidth, &info->MtxHeight); + if (pinnr <= 0 && pinnr != PIN_ANOMYM) + pinnr = PIN_UNKNOWN; + if (DryRun) { + if (pinnr > padvalid) + padvalid = pinnr; else if (pinnr == PIN_ANOMYM) padmech++; - } else if (pinnr != PIN_UNKNOWN) { - wxASSERT((pinnr >= 0 && pinnr <= padvalid) || pinnr == PIN_ANOMYM); - padlist[pinnr].startidx = idx; + } else if (pinnr != PIN_UNKNOWN) { + wxASSERT((pinnr >= 0 && pinnr <= padvalid) || pinnr == PIN_ANOMYM); + padlist[pinnr].startidx = idx; if (pinnr == PIN_ANOMYM) pinnr = padvalid + ++padmech; - wxASSERT(pinnr > 0 && pinnr < padcount); - GetToken(&line); /* ignore smd/thru_hole/np_thru_hole type */ - wxString shape = GetToken(&line); - wxString section = GetSection(line, wxT("at")); - if (section.length() > 0) { - padlist[pinnr].x = GetTokenDim(§ion, true); - padlist[pinnr].y = GetTokenDim(§ion, true); - if (section.length() > 0) - padlist[pinnr].angle = (long)GetTokenDouble(§ion); - else - padlist[pinnr].angle = 0; - } - section = GetSection(line, wxT("size")); - if (section.length() > 0) { - padlist[pinnr].width = GetTokenDim(§ion, true); - padlist[pinnr].height = GetTokenDim(§ion, true); - } - section = GetSection(line, wxT("drill")); - if (section.length() > 0) { - if (section.Left(4).Cmp(wxT("oval"))==0) { - GetToken(§ion); - padlist[pinnr].drillwidth = GetTokenDim(§ion, true); - padlist[pinnr].drillheight = GetTokenDim(§ion, true); - } else { - padlist[pinnr].drillwidth = GetTokenDim(§ion, true); - padlist[pinnr].drillheight = 0; - } - } - if (shape.Cmp(wxT("circle")) == 0) - padlist[pinnr].shape = 'C'; - else if (shape.Cmp(wxT("rect")) == 0) - padlist[pinnr].shape = 'R'; - else if (shape.Cmp(wxT("oval")) == 0) - padlist[pinnr].shape = 'O'; - else if (shape.Cmp(wxT("trapezoid")) == 0) - padlist[pinnr].shape = 'T'; - } - pinnr = PIN_UNKNOWN; - continue; - } - if (startidx == 0) - continue; - wxString token = GetToken(&line); - if (token.CmpNoCase(wxT("Po")) == 0) { - /* the pad position is relative to the module position, but in a - module library, the position is always presumed to be 0 (there may - be a non-zero position in the definition of a footprint module, but - its position is still presumed to be zero) */ - padx = GetTokenDim(&line, unit_mm); - pady = GetTokenDim(&line, unit_mm); - } else if (token.CmpNoCase(wxT("Sh")) == 0) { - wxString pin = GetToken(&line); - pinnr = GetPadNumber(pin, &info->MtxWidth, &info->MtxHeight); - if (pinnr <= 0 && pinnr != PIN_ANOMYM) - pinnr = PIN_UNKNOWN; - wxString shape = GetToken(&line); - padshape = toupper(shape[0]); - padwidth = GetTokenDim(&line, unit_mm); - padheight = GetTokenDim(&line, unit_mm); - GetToken(&line); /* ignore x-delta */ - GetToken(&line); /* ignore y-delta */ - padangle = GetTokenLong(&line); - } else if (token.CmpNoCase(wxT("Dr")) == 0) { - drillwidth = GetTokenDim(&line, unit_mm); - GetToken(&line); /* ignore drill offset */ - GetToken(&line); - token = GetToken(&line); - if (token == wxT('O')) { - drillwidth = GetTokenDim(&line, unit_mm); - drillheight = GetTokenDim(&line, unit_mm); - } - } - } /* for (running over the pads in the module) */ - } while (DryRun && padvalid > 0); /* if no numbered pad was found in the dry run, no need for a second run */ - - /* walk through the data to find the pin pitch */ - double drillsize = -1; - double pitchhor = -1, pitchver = -1; - CoordPair padsize[2]; - padsize[0] = CoordPair(-1, -1); - padsize[1] = CoordPair(-1, -1); - bool padrightangle[2] = { false, false }; - int horpin_base = 0, verpin_base = 0; - int horlevel = 0, verlevel = 0; - int padsizecount[2] = { 0, 0 }; - char padshape = '\0'; - for (int pinnr = 1; pinnr < padcount; pinnr++) { - if (padlist[pinnr].startidx == 0) - continue; - padlist[pinnr].rotate = false; /* preset */ - if (!padsize[0].Equal(0,0)) { - /* first pad is not yet set to "variable size" */ - if (padsize[0].Equal(-1,-1)) { - /* first pad is not yet set, set dimensions */ - padsize[0].Set(padlist[pinnr].width, padlist[pinnr].height); - padsizecount[0] += 1; - padrightangle[0] = padlist[pinnr].angle == 90 || padlist[pinnr].angle == 270; - } else if (padsize[0].Equal(padlist[pinnr].width, padlist[pinnr].height)) { - /* this pad has equal size to the first pad */ - padsizecount[0] += 1; - } else if (padsize[0].Equal(padlist[pinnr].height, padlist[pinnr].width)) { - /* this pad has equal size to the first pad after rotation by 90 degrees */ - padsizecount[0] += 1; - padlist[pinnr].rotate = true; - } else { - /* this pad does not match the first pad, check whether to - use the second pad */ - if (padsize[1].Equal(-1,-1)) { - /* second pad is not yet set, set dimensions */ - padsize[1].Set(padlist[pinnr].width, padlist[pinnr].height); - padsizecount[1] += 1; - padrightangle[1] = padlist[pinnr].angle == 90 || padlist[pinnr].angle == 270; - } else if (padsize[1].Equal(padlist[pinnr].width, padlist[pinnr].height)) { - /* this pad has equal size to the second pad */ - padsizecount[1] += 1; - } else if (padsize[1].Equal(padlist[pinnr].height, padlist[pinnr].width)) { - /* this pad has equal size to the second pad, after rotation by 90 degrees */ - padsizecount[1] += 1; - padlist[pinnr].rotate = true; - } else { - /* this pad mismatches the first and the second pads, set - both to "mismatch" */ - padsize[0].Set(0, 0); - padsize[1].Set(0, 0); - padrightangle[0] = padrightangle[1] = false; - } - } - } - if (padlist[pinnr - 1].startidx > 0) { - double dx = padlist[pinnr].x - padlist[pinnr - 1].x; - double dy = padlist[pinnr].y - padlist[pinnr - 1].y; - if (dx < 0) - dx = -dx; - if (dy < 0) - dy = -dy; - /* check horizontal pitch */ - if (horlevel < 2 && dx >= MIN_PITCH) { /* deltas smaller than this are not seen as pitch */ - int newlevel = (dy < MIN_PITCH) ? 2 : 1; - if (newlevel > horlevel) { - pitchhor = dx; - horlevel = newlevel; - horpin_base = pinnr; - } - } - /* check vertical pitch */ - if (verlevel < 2 && dy >= MIN_PITCH) { - int newlevel = (dx < MIN_PITCH) ? 2 : 1; - if (newlevel > verlevel) { - pitchver = dy; - verlevel = newlevel; - verpin_base = pinnr; - } - } - } - if (padshape == '\0') { - padshape = padlist[pinnr].shape; - } else if (padshape != padlist[pinnr].shape) { - if ((padshape == 'R' || padshape == 'S') && padlist[pinnr].shape == 'C' - && padsize[0].Equal(padlist[pinnr].width,padlist[pinnr].height)) - padshape = 'S'; /* first pad is square with the same dimension as the round pad */ - else if (padlist[pinnr].shape != 'R' || pinnr < padvalid) - padshape = 'v'; /* multiple pad shapes, but make an exception for the centre pad */ - } - if (drillsize < -EPSILON && padlist[pinnr].drillwidth > EPSILON) - drillsize = padlist[pinnr].drillwidth; - else if (padlist[pinnr].drillwidth > EPSILON && (drillsize < padlist[pinnr].drillwidth - EPSILON || drillsize > padlist[pinnr].drillwidth + EPSILON)) - drillsize = 0; - } /* for (running over pin numbers) */ - - /* for any pad that has the rotate flag set, swap the width and height and - add 90 degrees to the rotation value */ - for (int pinnr = 1; pinnr < padcount; pinnr++) { - if (padlist[pinnr].startidx == 0 || !padlist[pinnr].rotate) - continue; - for (unsigned idx = padlist[pinnr].startidx; idx < module->Count(); idx++) { - wxString line = module->Item(idx); - wxString keyword = GetToken(&line); - wxASSERT(keyword.CmpNoCase(wxT("$EndPAD")) != 0); /* "Sh" must be found before end of pad */ - if (keyword.CmpNoCase(wxT("Sh")) == 0) { - /* handle "Sh" to swap the width and height, and add a 90 degree rotation */ - wxString name = GetToken(&line); - wxString type = GetToken(&line); - wxString width = GetToken(&line); - wxString height = GetToken(&line); - wxString xdelta = GetToken(&line); - wxString ydelta = GetToken(&line); - long rot = GetTokenLong(&line); - rot += 900; - if (rot > 3600) - rot -= 3600; - module->Item(idx) = wxString::Format(wxT("%s %s %s %s %s %s %s %ld"), - keyword.c_str(), name.c_str(), type.c_str(), - height.c_str(), width.c_str(), xdelta.c_str(), ydelta.c_str(), - rot); - break; /* no need to search further */ - } else if (keyword.CmpNoCase(wxT("(pad")) == 0) { - wxString section = GetSection(line, wxT("at")); - if (section.length() > 0) { - wxString x = GetToken(§ion); - wxString y = GetToken(§ion); - double rot = 0.0; - if (section.length() > 0) - rot = GetTokenDouble(§ion); - rot += 90.0; - if (rot > 360.0) - rot -= 360.0; - section = wxString::Format(wxT("%s %s %.1f"), x.c_str(), y.c_str(), rot); - SetSection(line, wxT("at"), section); - } - section = GetSection(line, wxT("size")); - if (section.length() > 0) { - wxString width = GetToken(§ion); - wxString height = GetToken(§ion); - section = height + wxT(" ") + width; - SetSection(line, wxT("size"), section); - } - } - } - } - - /* count the number of pads in a row span or column span */ - int pinhor_count = 0, pinver_count = 0; - for (int pinnr = 1; pinnr < padcount; pinnr++) { - if (padlist[pinnr].startidx <= 0) - continue; - if (pitchhor > EPSILON && Equal(padlist[pinnr].y, padlist[horpin_base].y, TOLERANCE)) - pinhor_count++; - if (pitchver > EPSILON && Equal(padlist[pinnr].x, padlist[verpin_base].x, TOLERANCE)) - pinver_count++; - } - wxASSERT(pinhor_count == 0 && pitchhor <= EPSILON || pinhor_count > 0 && pitchhor > EPSILON); - wxASSERT(pinver_count == 0 && pitchver <= EPSILON || pinver_count > 0 && pitchver > EPSILON); - /* when both a horizontal span and a vertical span are found: - - if one of the spans has only two pins, the pitch is in the other direction - - otherwise take the smaller of the two - - on equal size: prefer vertical on most shapes, but prefer horizontal on grid arrays - */ - - /* copy most of the information now */ - info->PadCount = padvalid; - info->PadShape = padshape; - info->DrillSize = (drillsize > EPSILON) ? drillsize : 0; - if (pitchhor > EPSILON /* hor. pitch is set */ - && (pitchver <= EPSILON /* no ver. pitch */ - || pitchhor < pitchver - EPSILON /* or hor. pitch is smaller */ - || (Equal(pitchhor, pitchver) && info->MtxWidth > 0)) /* or hor. & ver. pitch are the same and it's a grid array */ - && (pinhor_count > 2 || pinver_count <= 2)) /* hor. pitch has > 2 pads while ver. pitch has 2 pads (or no ver. pitch) */ - { - info->Pitch = pitchhor; - info->PitchVertical = false; - info->PadLines = 1; /* assume, for now, may be adjusted later */ - wxASSERT(horpin_base > 0); - wxASSERT(padlist[horpin_base - 1].startidx > 0 && padlist[horpin_base].startidx > 0); - info->PitchPins[0] = CoordPair(padlist[horpin_base - 1].x, padlist[horpin_base - 1].y); - info->PitchPins[1] = CoordPair(padlist[horpin_base].x, padlist[horpin_base].y); - } else if (pitchver > EPSILON) { - info->Pitch = pitchver; - info->PitchVertical = true; - info->PadLines = 1; /* assume, for now, may be adjusted later */ - wxASSERT(verpin_base > 0); - wxASSERT(padlist[verpin_base - 1].startidx > 0 && padlist[verpin_base].startidx > 0); - info->PitchPins[0] = CoordPair(padlist[verpin_base - 1].x, padlist[verpin_base - 1].y); - info->PitchPins[1] = CoordPair(padlist[verpin_base].x, padlist[verpin_base].y); - } - /* avoid invalid values for the pad sizes */ - if (padsize[0].Equal(-1, -1)) - padsize[0].Set(0, 0); - if (padsize[1].Equal(-1, -1)) - padsize[1].Set(0, 0); - /* check whether to swap the pad numbers (the primary pad must be the one used most) */ - if (!info->PadSize[0].Equal(0,0) && padsizecount[1] > padsizecount[0]) { - info->PadSize[0] = padsize[1]; - info->PadSize[1] = padsize[0]; - info->PadRightAngle[0] = padrightangle[1]; - info->PadRightAngle[1] = padrightangle[0]; + wxASSERT(pinnr > 0 && pinnr < padcount); + GetToken(&line); /* ignore smd/thru_hole/np_thru_hole type */ + wxString shape = GetToken(&line); + wxString section = GetSection(line, wxT("at")); + if (section.length() > 0) { + padlist[pinnr].x = GetTokenDim(§ion, true); + padlist[pinnr].y = GetTokenDim(§ion, true); + if (section.length() > 0) + padlist[pinnr].angle = (long)GetTokenDouble(§ion); + else + padlist[pinnr].angle = 0; + } + section = GetSection(line, wxT("size")); + if (section.length() > 0) { + padlist[pinnr].width = GetTokenDim(§ion, true); + padlist[pinnr].height = GetTokenDim(§ion, true); + } + section = GetSection(line, wxT("drill")); + if (section.length() > 0) { + if (section.Left(4).Cmp(wxT("oval"))==0) { + GetToken(§ion); + padlist[pinnr].drillwidth = GetTokenDim(§ion, true); + padlist[pinnr].drillheight = GetTokenDim(§ion, true); + } else { + padlist[pinnr].drillwidth = GetTokenDim(§ion, true); + padlist[pinnr].drillheight = 0; + } + } + if (shape.Cmp(wxT("circle")) == 0) + padlist[pinnr].shape = 'C'; + else if (shape.Cmp(wxT("rect")) == 0) + padlist[pinnr].shape = 'R'; + else if (shape.Cmp(wxT("oval")) == 0) + padlist[pinnr].shape = 'O'; + else if (shape.Cmp(wxT("trapezoid")) == 0) + padlist[pinnr].shape = 'T'; + } + pinnr = PIN_UNKNOWN; + continue; + } + if (startidx == 0) + continue; + wxString token = GetToken(&line); + if (token.CmpNoCase(wxT("Po")) == 0) { + /* the pad position is relative to the module position, but in a + module library, the position is always presumed to be 0 (there may + be a non-zero position in the definition of a footprint module, but + its position is still presumed to be zero) */ + padx = GetTokenDim(&line, unit_mm); + pady = GetTokenDim(&line, unit_mm); + } else if (token.CmpNoCase(wxT("Sh")) == 0) { + wxString pin = GetToken(&line); + pinnr = GetPadNumber(pin, &info->MtxWidth, &info->MtxHeight); + if (pinnr <= 0 && pinnr != PIN_ANOMYM) + pinnr = PIN_UNKNOWN; + wxString shape = GetToken(&line); + padshape = toupper(shape[0]); + padwidth = GetTokenDim(&line, unit_mm); + padheight = GetTokenDim(&line, unit_mm); + GetToken(&line); /* ignore x-delta */ + GetToken(&line); /* ignore y-delta */ + padangle = GetTokenLong(&line); + } else if (token.CmpNoCase(wxT("Dr")) == 0) { + drillwidth = GetTokenDim(&line, unit_mm); + GetToken(&line); /* ignore drill offset */ + GetToken(&line); + token = GetToken(&line); + if (token == wxT('O')) { + drillwidth = GetTokenDim(&line, unit_mm); + drillheight = GetTokenDim(&line, unit_mm); + } + } + } /* for (running over the pads in the module) */ + } while (DryRun && padvalid > 0); /* if no numbered pad was found in the dry run, no need for a second run */ + + /* walk through the data to find the pin pitch */ + double drillsize = -1; + double pitchhor = -1, pitchver = -1; + CoordPair padsize[2]; + padsize[0] = CoordPair(-1, -1); + padsize[1] = CoordPair(-1, -1); + bool padrightangle[2] = { false, false }; + int horpin_base = 0, verpin_base = 0; + int horlevel = 0, verlevel = 0; + int padsizecount[2] = { 0, 0 }; + char padshape = '\0'; + for (int pinnr = 1; pinnr < padcount; pinnr++) { + if (padlist[pinnr].startidx == 0) + continue; + padlist[pinnr].rotate = false; /* preset */ + if (!padsize[0].Equal(0,0)) { + /* first pad is not yet set to "variable size" */ + if (padsize[0].Equal(-1,-1)) { + /* first pad is not yet set, set dimensions */ + padsize[0].Set(padlist[pinnr].width, padlist[pinnr].height); + padsizecount[0] += 1; + padrightangle[0] = padlist[pinnr].angle == 90 || padlist[pinnr].angle == 270; + } else if (padsize[0].Equal(padlist[pinnr].width, padlist[pinnr].height)) { + /* this pad has equal size to the first pad */ + padsizecount[0] += 1; + } else if (padsize[0].Equal(padlist[pinnr].height, padlist[pinnr].width)) { + /* this pad has equal size to the first pad after rotation by 90 degrees */ + padsizecount[0] += 1; + padlist[pinnr].rotate = true; + } else { + /* this pad does not match the first pad, check whether to + use the second pad */ + if (padsize[1].Equal(-1,-1)) { + /* second pad is not yet set, set dimensions */ + padsize[1].Set(padlist[pinnr].width, padlist[pinnr].height); + padsizecount[1] += 1; + padrightangle[1] = padlist[pinnr].angle == 90 || padlist[pinnr].angle == 270; + } else if (padsize[1].Equal(padlist[pinnr].width, padlist[pinnr].height)) { + /* this pad has equal size to the second pad */ + padsizecount[1] += 1; + } else if (padsize[1].Equal(padlist[pinnr].height, padlist[pinnr].width)) { + /* this pad has equal size to the second pad, after rotation by 90 degrees */ + padsizecount[1] += 1; + padlist[pinnr].rotate = true; + } else { + /* this pad mismatches the first and the second pads, set + both to "mismatch" */ + padsize[0].Set(0, 0); + padsize[1].Set(0, 0); + padrightangle[0] = padrightangle[1] = false; + } + } + } + if (padlist[pinnr - 1].startidx > 0) { + double dx = padlist[pinnr].x - padlist[pinnr - 1].x; + double dy = padlist[pinnr].y - padlist[pinnr - 1].y; + if (dx < 0) + dx = -dx; + if (dy < 0) + dy = -dy; + /* check horizontal pitch */ + if (horlevel < 2 && dx >= MIN_PITCH) { /* deltas smaller than this are not seen as pitch */ + int newlevel = (dy < MIN_PITCH) ? 2 : 1; + if (newlevel > horlevel) { + pitchhor = dx; + horlevel = newlevel; + horpin_base = pinnr; + } + } + /* check vertical pitch */ + if (verlevel < 2 && dy >= MIN_PITCH) { + int newlevel = (dx < MIN_PITCH) ? 2 : 1; + if (newlevel > verlevel) { + pitchver = dy; + verlevel = newlevel; + verpin_base = pinnr; + } + } + } + if (padshape == '\0') { + padshape = padlist[pinnr].shape; + } else if (padshape != padlist[pinnr].shape) { + if ((padshape == 'R' || padshape == 'S') && padlist[pinnr].shape == 'C' + && padsize[0].Equal(padlist[pinnr].width,padlist[pinnr].height)) + padshape = 'S'; /* first pad is square with the same dimension as the round pad */ + else if (padlist[pinnr].shape != 'R' || pinnr < padvalid) + padshape = 'v'; /* multiple pad shapes, but make an exception for the centre pad */ + } + if (drillsize < -EPSILON && padlist[pinnr].drillwidth > EPSILON) + drillsize = padlist[pinnr].drillwidth; + else if (padlist[pinnr].drillwidth > EPSILON && (drillsize < padlist[pinnr].drillwidth - EPSILON || drillsize > padlist[pinnr].drillwidth + EPSILON)) + drillsize = 0; + } /* for (running over pin numbers) */ + + /* for any pad that has the rotate flag set, swap the width and height and + add 90 degrees to the rotation value */ + for (int pinnr = 1; pinnr < padcount; pinnr++) { + if (padlist[pinnr].startidx == 0 || !padlist[pinnr].rotate) + continue; + for (unsigned idx = padlist[pinnr].startidx; idx < module->Count(); idx++) { + wxString line = module->Item(idx); + wxString keyword = GetToken(&line); + wxASSERT(keyword.CmpNoCase(wxT("$EndPAD")) != 0); /* "Sh" must be found before end of pad */ + if (keyword.CmpNoCase(wxT("Sh")) == 0) { + /* handle "Sh" to swap the width and height, and add a 90 degree rotation */ + wxString name = GetToken(&line); + wxString type = GetToken(&line); + wxString width = GetToken(&line); + wxString height = GetToken(&line); + wxString xdelta = GetToken(&line); + wxString ydelta = GetToken(&line); + long rot = GetTokenLong(&line); + rot += 900; + if (rot > 3600) + rot -= 3600; + module->Item(idx) = wxString::Format(wxT("%s %s %s %s %s %s %s %ld"), + keyword.c_str(), name.c_str(), type.c_str(), + height.c_str(), width.c_str(), xdelta.c_str(), ydelta.c_str(), + rot); + break; /* no need to search further */ + } else if (keyword.CmpNoCase(wxT("(pad")) == 0) { + wxString section = GetSection(line, wxT("at")); + if (section.length() > 0) { + wxString x = GetToken(§ion); + wxString y = GetToken(§ion); + double rot = 0.0; + if (section.length() > 0) + rot = GetTokenDouble(§ion); + rot += 90.0; + if (rot > 360.0) + rot -= 360.0; + section = wxString::Format(wxT("%s %s %.1f"), x.c_str(), y.c_str(), rot); + SetSection(line, wxT("at"), section); + } + section = GetSection(line, wxT("size")); + if (section.length() > 0) { + wxString width = GetToken(§ion); + wxString height = GetToken(§ion); + section = height + wxT(" ") + width; + SetSection(line, wxT("size"), section); + } + } + } + } + + /* count the number of pads in a row span or column span */ + int pinhor_count = 0, pinver_count = 0; + for (int pinnr = 1; pinnr < padcount; pinnr++) { + if (padlist[pinnr].startidx <= 0) + continue; + if (pitchhor > EPSILON && Equal(padlist[pinnr].y, padlist[horpin_base].y, TOLERANCE)) + pinhor_count++; + if (pitchver > EPSILON && Equal(padlist[pinnr].x, padlist[verpin_base].x, TOLERANCE)) + pinver_count++; + } + wxASSERT(pinhor_count == 0 && pitchhor <= EPSILON || pinhor_count > 0 && pitchhor > EPSILON); + wxASSERT(pinver_count == 0 && pitchver <= EPSILON || pinver_count > 0 && pitchver > EPSILON); + /* when both a horizontal span and a vertical span are found: + - if one of the spans has only two pins, the pitch is in the other direction + - otherwise take the smaller of the two + - on equal size: prefer vertical on most shapes, but prefer horizontal on grid arrays + */ + + /* copy most of the information now */ + info->PadCount = padvalid; + info->PadShape = padshape; + info->DrillSize = (drillsize > EPSILON) ? drillsize : 0; + if (pitchhor > EPSILON /* hor. pitch is set */ + && (pitchver <= EPSILON /* no ver. pitch */ + || pitchhor < pitchver - EPSILON /* or hor. pitch is smaller */ + || (Equal(pitchhor, pitchver) && info->MtxWidth > 0)) /* or hor. & ver. pitch are the same and it's a grid array */ + && (pinhor_count > 2 || pinver_count <= 2)) /* hor. pitch has > 2 pads while ver. pitch has 2 pads (or no ver. pitch) */ + { + info->Pitch = pitchhor; + info->PitchVertical = false; + info->PadLines = 1; /* assume, for now, may be adjusted later */ + wxASSERT(horpin_base > 0); + wxASSERT(padlist[horpin_base - 1].startidx > 0 && padlist[horpin_base].startidx > 0); + info->PitchPins[0] = CoordPair(padlist[horpin_base - 1].x, padlist[horpin_base - 1].y); + info->PitchPins[1] = CoordPair(padlist[horpin_base].x, padlist[horpin_base].y); + } else if (pitchver > EPSILON) { + info->Pitch = pitchver; + info->PitchVertical = true; + info->PadLines = 1; /* assume, for now, may be adjusted later */ + wxASSERT(verpin_base > 0); + wxASSERT(padlist[verpin_base - 1].startidx > 0 && padlist[verpin_base].startidx > 0); + info->PitchPins[0] = CoordPair(padlist[verpin_base - 1].x, padlist[verpin_base - 1].y); + info->PitchPins[1] = CoordPair(padlist[verpin_base].x, padlist[verpin_base].y); + } + /* avoid invalid values for the pad sizes */ + if (padsize[0].Equal(-1, -1)) + padsize[0].Set(0, 0); + if (padsize[1].Equal(-1, -1)) + padsize[1].Set(0, 0); + /* check whether to swap the pad numbers (the primary pad must be the one used most) */ + if (!info->PadSize[0].Equal(0,0) && padsizecount[1] > padsizecount[0]) { + info->PadSize[0] = padsize[1]; + info->PadSize[1] = padsize[0]; + info->PadRightAngle[0] = padrightangle[1]; + info->PadRightAngle[1] = padrightangle[0]; int t = padsizecount[0]; padsizecount[0] = padsizecount[1]; padsizecount[1] = t; - } else { - info->PadSize[0] = padsize[0]; - info->PadSize[1] = padsize[1]; - info->PadRightAngle[0] = padrightangle[0]; - info->PadRightAngle[1] = padrightangle[1]; - } - /* check whether the primary pad is also the one attached to the pitch */ - if (info->Pitch > EPSILON) { - int pin = info->PitchVertical ? (verpin_base - 1) : (horpin_base - 1); - wxASSERT(pin >= 0); - wxASSERT(padlist[pin].startidx > 0); - if (padsize[0].Equal(padlist[pin].width, padlist[pin].height) || padsize[0].Equal(padlist[pin].height, padlist[pin].width)) - info->RegPadCount = padsizecount[0]; - else if (padsize[1].Equal(padlist[pin].width, padlist[pin].height) || padsize[1].Equal(padlist[pin].height, padlist[pin].width)) - info->RegPadCount = padsizecount[1]; - } - - if (padvalid > 2 && pitchhor > EPSILON && pitchver > EPSILON) { - /* components have a span as well as a pitch, the span is detected now */ - if (padvalid == 3) { - /* detect SOT23 and similar, as the pitch is detected incorrectly on these parts */ - if (Equal(padlist[1].x, padlist[2].x, TOLERANCE) && verpin_base == 2) { - double d3 = padlist[3].y - padlist[1].y; - double d2 = padlist[2].y - padlist[1].y; - if (Equal(d3, d2 / 2, TOLERANCE)) { - info->SOT23pitch = true; - verpin_base = 3; - info->Pitch = pitchver / 2; - info->PitchVertical = true; - info->PitchPins[1] = CoordPair(padlist[verpin_base].x, padlist[verpin_base].y); - pitchver = 0; /* clear, so the horizontal "pitch" will be detected as the span */ - } - } else if (Equal(padlist[1].y, padlist[2].y, TOLERANCE) && horpin_base == 2) { - /* incorrectly oriented SOT23 (or similar) */ - double d3 = padlist[3].x - padlist[1].x; - double d2 = padlist[2].x - padlist[1].x; - if (Equal(d3, d2 / 2, TOLERANCE)) { - info->SOT23pitch = true; - horpin_base = 3; - info->Pitch = pitchhor / 2; - info->PitchVertical = false; - info->PitchPins[1] = CoordPair(padlist[horpin_base].x, padlist[horpin_base].y); - pitchhor = 0; /* clear, so the vertical "pitch" will be detected as the span */ - } - } - } - - /* if the detected horizontal pitch is different from the vertical pitch, - then the "pitch" is set to one of these (already handled) and the single - span is in the other direction (horizontal pitch -> vertical span, and - vice versa); the case where the horizontal and vertical "pitch" are - equal is handled separately */ - if (!Equal(pitchhor, pitchver)) { - wxASSERT(info->Pitch > EPSILON); - if (info->PitchVertical) { - info->SpanHor = pitchhor; - wxASSERT(horpin_base > 1); - wxASSERT(padlist[horpin_base - 1].startidx > 0 && padlist[horpin_base].startidx > 0); - info->SpanHorPins[0] = CoordPair(padlist[horpin_base - 1].x, padlist[horpin_base - 1].y); - info->SpanHorPins[1] = CoordPair(padlist[horpin_base].x, padlist[horpin_base].y); - } else { - info->SpanVer = pitchver; - wxASSERT(verpin_base > 0); - wxASSERT(padlist[verpin_base - 1].startidx > 0 && padlist[verpin_base].startidx > 0); - info->SpanVerPins[0] = CoordPair(padlist[verpin_base - 1].x, padlist[verpin_base - 1].y); - info->SpanVerPins[1] = CoordPair(padlist[verpin_base].x, padlist[verpin_base].y); - } - } else { - /* so the detected pitch is equal for horizontal and vertical, this - can be a quad-pack or a pin array */ - wxASSERT(pitchhor - pitchver >= -EPSILON && pitchhor - pitchver <= EPSILON); - /* first check for a pin array */ - bool matcharray = true; - int colcount = 0, rowcount = 0; - wxASSERT(verpin_base > 0); - wxASSERT(padlist[verpin_base].startidx > 0); - for (int pin1 = 1; matcharray && pin1 <= padvalid; pin1++) { - if (padlist[pin1].startidx > 0 && Equal(padlist[pin1].x, padlist[verpin_base].x, TOLERANCE)) { - /* pin1 is in the same vertical row as where the vertical pitch - was detected */ - rowcount++; - bool matchhor = false; - for (int pin2 = 1; !matchhor && pin2 <= padvalid; pin2++) { - if (pin2 != pin1 && padlist[pin2].startidx > 0 - && Equal(padlist[pin2].y, padlist[pin1].y, TOLERANCE)) { - /* pin2 is in the same horizontal row as pin1, check the pitch */ - matchhor = Equal(padlist[pin2].x, padlist[pin1].x + pitchhor, TOLERANCE) - || Equal(padlist[pin2].x + pitchhor, padlist[pin1].x, TOLERANCE); - } - } - if (!matchhor) - matcharray = false; /* no opposing pin at the correct pitch was found for every pin */ - } - } - wxASSERT(horpin_base > 0); - wxASSERT(padlist[horpin_base].startidx > 0); - for (int pin1 = 1; matcharray && pin1 <= padvalid; pin1++) { - if (padlist[pin1].startidx > 0 && Equal(padlist[pin1].y, padlist[horpin_base].y, TOLERANCE)) { - /* pin1 is in the same horizontal row as where the horizontal pitch - was detected */ - colcount++; - bool matchver = false; - for (int pin2 = 1; !matchver && pin2 <= padvalid; pin2++) { - if (pin2 != pin1 && padlist[pin2].startidx > 0 - && Equal(padlist[pin2].x, padlist[pin1].x, TOLERANCE)) { - /* pin2 is in the same vertical row as pin1, check the pitch */ - matchver = Equal(padlist[pin2].y, padlist[pin1].y + pitchver, TOLERANCE) - || Equal(padlist[pin2].y + pitchver, padlist[pin1].y, TOLERANCE); - } - } - if (!matchver) - matcharray = false; /* no opposing pin at the correct pitch was found for every pin */ - } - } - if (matcharray) { - if (colcount == 2) { - info->PadLines = 2; - info->Pitch = pitchver; - info->PitchVertical = true; - /* for pin arrays, the pin numbering is often in a zig-zag style; for - the span, this is handled here, for the pitch, it is handled later - in the routine */ - wxASSERT(horpin_base > 1 && padlist[horpin_base].startidx > 0); - for (int pinnr = horpin_base - 1; pinnr > 0; pinnr--) { - if (padlist[pinnr].startidx > 0 && Equal(padlist[pinnr].y, padlist[horpin_base].y, TOLERANCE)) { - info->SpanHor = pitchhor; - info->SpanHorPins[0] = CoordPair(padlist[pinnr].x, padlist[pinnr].y); - info->SpanHorPins[1] = CoordPair(padlist[horpin_base].x, padlist[horpin_base].y); - break; - } - } - } else if (rowcount == 2) { - info->PadLines = 2; - info->Pitch = pitchhor; - info->PitchVertical = false; - wxASSERT(verpin_base > 1 && padlist[verpin_base].startidx > 0); - for (int pinnr = verpin_base - 1; pinnr > 0; pinnr--) { - if (padlist[pinnr].startidx > 0 && Equal(padlist[pinnr].x, padlist[verpin_base].x, TOLERANCE)) { - info->SpanVer = pitchver; - info->SpanVerPins[0] = CoordPair(padlist[pinnr].x, padlist[pinnr].y); - info->SpanVerPins[1] = CoordPair(padlist[verpin_base].x, padlist[verpin_base].y); - break; - } - } - } else { - /* this is a BGA or PGA, we cannot currently edit these */ - info->PitchValid = false; - } - } else { - /* this is a quad-pack, meaning that the spans must be separately detected */ - info->PadLines = 4; /* this is a quad-pack */ - /* find horizontal span */ - wxASSERT(verpin_base > 0); - wxASSERT(padlist[verpin_base].startidx > 0); - for (int pinnr = 1; pinnr <= padvalid; pinnr++) { - if (padlist[pinnr].startidx > 0 - && Equal(padlist[pinnr].x, padlist[verpin_base].x, TOLERANCE) - && padlist[pinnr].y > padlist[verpin_base].y) - verpin_base = pinnr; - } - for (int pinnr = 1; pinnr <= padvalid; pinnr++) { - if (padlist[pinnr].startidx > 0 && pinnr != verpin_base && Equal(padlist[pinnr].y, padlist[verpin_base].y, TOLERANCE)) { - int lo = verpin_base; - int hi = pinnr; - if (padlist[lo].x > padlist[hi].x) { - hi = verpin_base; - lo = pinnr; - } - info->SpanHorPins[0] = CoordPair(padlist[lo].x, padlist[lo].y); - info->SpanHorPins[1] = CoordPair(padlist[hi].x, padlist[hi].y); - info->SpanHor = padlist[hi].x - padlist[lo].x; - wxASSERT(info->SpanHor > 0); - break; - } - } - /* find vertical span */ - wxASSERT(horpin_base > 0); - wxASSERT(padlist[horpin_base].startidx > 0); - for (int pinnr = 1; pinnr <= padvalid; pinnr++) { - if (padlist[pinnr].startidx > 0 - && Equal(padlist[pinnr].y, padlist[horpin_base].y, TOLERANCE) - && padlist[pinnr].x > padlist[verpin_base].x) - horpin_base = pinnr; - } - for (int pinnr = 1; pinnr <= padvalid; pinnr++) { - if (padlist[pinnr].startidx > 0 && pinnr != horpin_base && Equal(padlist[pinnr].x, padlist[horpin_base].x, TOLERANCE)) { - int lo = horpin_base; - int hi = pinnr; - if (padlist[lo].y > padlist[hi].y) { - hi = horpin_base; - lo = pinnr; - } - info->SpanVerPins[0] = CoordPair(padlist[lo].x, padlist[lo].y); - info->SpanVerPins[1] = CoordPair(padlist[hi].x, padlist[hi].y); - info->SpanVer = padlist[hi].y - padlist[lo].y; - wxASSERT(info->SpanVer > 0); - break; - } - } - } /* !matcharray */ - } /* pitchhor == pitchver */ - } /* more than 2 pins and 2 pitches/spans detected */ - - /* To be able to adjust the pitch, also verify the number of lines (or - rows and columns) that are "pitch-separated". If both the detected - horizontal and vertical pitch are equal, we may safely assume that - the number is 4; this was already handled. But a DIL lay-out needs - to be checked for explicitly. Fortunately this is easy: it will have - both a pitch and a span (in one direction). */ - if (info->PadLines == 1 && padvalid > 3) { - /* a 3-pin SOT23 must remain single line */ - wxASSERT(info->Pitch > EPSILON); - if (info->SpanHor > EPSILON || info->SpanVer > EPSILON) - info->PadLines = 2; - } - /* However, if the number of "regular" pads do fit in the number of lines - for these pads, clear all (to mark the pitch as "non-detected", and - therefore non-editable) */ - if (info->PadLines > 1 && info->RegPadCount % info->PadLines != 0) { - /* we do need to make an exception for 5-pin SOT23 variants */ - if (info->RegPadCount == 5 - && Equal(padlist[1].x, padlist[2].x, TOLERANCE) /* pins 1, 2 and 3 must be vertically aligned */ - && Equal(padlist[1].x, padlist[3].x, TOLERANCE) - && Equal(padlist[4].x, padlist[5].x, TOLERANCE) /* pins 4 and 5 must be vertically aligned */ - && Equal(padlist[1].y, padlist[5].y, TOLERANCE) /* pins 1 and 5 must be horizontally aligned */ - && Equal(padlist[3].y, padlist[4].y, TOLERANCE)) /* pins 2 and 4 must be horizontally aligned */ - { - info->SOT23pitch = true; /* 5-pin SOT23 */ - } else { - info->RegPadCount = 0; - info->PadLines = 0; - } - } - /* for dual-row pin arrays, the pin numbering is often in a zig-zag style */ - if (info->PadLines == 2) { - wxASSERT(info->Pitch > EPSILON); - if (info->PitchVertical) { - for (int pinnr = verpin_base - 1; pinnr > 0; pinnr--) { - if (padlist[pinnr].startidx > 0 && Equal(padlist[pinnr].x, info->PitchPins[1].GetX(), TOLERANCE)) { - info->PitchPins[0] = CoordPair(padlist[pinnr].x, padlist[pinnr].y); - info->PadSequence = verpin_base - pinnr; - break; - } - } - } else { - for (int pinnr = horpin_base - 1; pinnr > 0; pinnr--) { - if (padlist[pinnr].startidx > 0 && Equal(padlist[pinnr].y, info->PitchPins[1].GetY(), TOLERANCE)) { - info->PitchPins[0] = CoordPair(padlist[pinnr].x, padlist[pinnr].y); - info->PadSequence = horpin_base - pinnr; - break; - } - } - } - } - /* The pitch may not be edited if the footprint is not centred; so this should - be verified too */ - info->OriginCentred = true; - if (info->SpanHor > 0 && - !Equal(-info->SpanHorPins[0].GetX(), info->SpanHorPins[1].GetX())) - info->OriginCentred = false; - if (info->SpanVer > 0 && - !Equal(-info->SpanVerPins[0].GetY(), info->SpanVerPins[1].GetY())) - info->OriginCentred = false; - - /* For grid arrays (BGA/PGA), check for a centre void (because the number - for pins needs to be reduced by the pins in the centre void) */ - if (info->MtxWidth > 0 && info->MtxHeight > 0) { - int c1 = -1, r1 = -1, c2 = -1, r2 = -1; - for (int pinnr = 1; pinnr <= padvalid; pinnr++) { - if (padlist[pinnr].startidx <= 0) { - int row = (pinnr - 1) / info->MtxWidth; /* zero-based row */ - int col = pinnr - row * info->MtxWidth - 1; /* zero-based column */ - if (c1 == -1 || col < c1) - c1 = col; - if (c2 == -1 || col > c2) - c2 = col; - if (r1 == -1 || row < r1) - r1 = row; - if (r2 == -1 || row > r2) - r2 = row; - } - } - if (c1 >= 0) - info->MtxCentreX = c2 - c1 + 1; - if (r1 >= 0) - info->MtxCentreY = r2 - r1 + 1; - info->PadCount -= info->MtxCentreX * info->MtxCentreY; - } + } else { + info->PadSize[0] = padsize[0]; + info->PadSize[1] = padsize[1]; + info->PadRightAngle[0] = padrightangle[0]; + info->PadRightAngle[1] = padrightangle[1]; + } + /* check whether the primary pad is also the one attached to the pitch */ + if (info->Pitch > EPSILON) { + int pin = info->PitchVertical ? (verpin_base - 1) : (horpin_base - 1); + wxASSERT(pin >= 0); + wxASSERT(padlist[pin].startidx > 0); + if (padsize[0].Equal(padlist[pin].width, padlist[pin].height) || padsize[0].Equal(padlist[pin].height, padlist[pin].width)) + info->RegPadCount = padsizecount[0]; + else if (padsize[1].Equal(padlist[pin].width, padlist[pin].height) || padsize[1].Equal(padlist[pin].height, padlist[pin].width)) + info->RegPadCount = padsizecount[1]; + } + + if (padvalid > 2 && pitchhor > EPSILON && pitchver > EPSILON) { + /* components have a span as well as a pitch, the span is detected now */ + if (padvalid == 3) { + /* detect SOT23 and similar, as the pitch is detected incorrectly on these parts */ + if (Equal(padlist[1].x, padlist[2].x, TOLERANCE) && verpin_base == 2) { + double d3 = padlist[3].y - padlist[1].y; + double d2 = padlist[2].y - padlist[1].y; + if (Equal(d3, d2 / 2, TOLERANCE)) { + info->SOT23pitch = true; + verpin_base = 3; + info->Pitch = pitchver / 2; + info->PitchVertical = true; + info->PitchPins[1] = CoordPair(padlist[verpin_base].x, padlist[verpin_base].y); + pitchver = 0; /* clear, so the horizontal "pitch" will be detected as the span */ + } + } else if (Equal(padlist[1].y, padlist[2].y, TOLERANCE) && horpin_base == 2) { + /* incorrectly oriented SOT23 (or similar) */ + double d3 = padlist[3].x - padlist[1].x; + double d2 = padlist[2].x - padlist[1].x; + if (Equal(d3, d2 / 2, TOLERANCE)) { + info->SOT23pitch = true; + horpin_base = 3; + info->Pitch = pitchhor / 2; + info->PitchVertical = false; + info->PitchPins[1] = CoordPair(padlist[horpin_base].x, padlist[horpin_base].y); + pitchhor = 0; /* clear, so the vertical "pitch" will be detected as the span */ + } + } + } + + /* if the detected horizontal pitch is different from the vertical pitch, + then the "pitch" is set to one of these (already handled) and the single + span is in the other direction (horizontal pitch -> vertical span, and + vice versa); the case where the horizontal and vertical "pitch" are + equal is handled separately */ + if (!Equal(pitchhor, pitchver)) { + wxASSERT(info->Pitch > EPSILON); + if (info->PitchVertical) { + info->SpanHor = pitchhor; + wxASSERT(horpin_base > 1); + wxASSERT(padlist[horpin_base - 1].startidx > 0 && padlist[horpin_base].startidx > 0); + info->SpanHorPins[0] = CoordPair(padlist[horpin_base - 1].x, padlist[horpin_base - 1].y); + info->SpanHorPins[1] = CoordPair(padlist[horpin_base].x, padlist[horpin_base].y); + } else { + info->SpanVer = pitchver; + wxASSERT(verpin_base > 0); + wxASSERT(padlist[verpin_base - 1].startidx > 0 && padlist[verpin_base].startidx > 0); + info->SpanVerPins[0] = CoordPair(padlist[verpin_base - 1].x, padlist[verpin_base - 1].y); + info->SpanVerPins[1] = CoordPair(padlist[verpin_base].x, padlist[verpin_base].y); + } + } else { + /* so the detected pitch is equal for horizontal and vertical, this + can be a quad-pack or a pin array */ + wxASSERT(pitchhor - pitchver >= -EPSILON && pitchhor - pitchver <= EPSILON); + /* first check for a pin array */ + bool matcharray = true; + int colcount = 0, rowcount = 0; + wxASSERT(verpin_base > 0); + wxASSERT(padlist[verpin_base].startidx > 0); + for (int pin1 = 1; matcharray && pin1 <= padvalid; pin1++) { + if (padlist[pin1].startidx > 0 && Equal(padlist[pin1].x, padlist[verpin_base].x, TOLERANCE)) { + /* pin1 is in the same vertical row as where the vertical pitch + was detected */ + rowcount++; + bool matchhor = false; + for (int pin2 = 1; !matchhor && pin2 <= padvalid; pin2++) { + if (pin2 != pin1 && padlist[pin2].startidx > 0 + && Equal(padlist[pin2].y, padlist[pin1].y, TOLERANCE)) { + /* pin2 is in the same horizontal row as pin1, check the pitch */ + matchhor = Equal(padlist[pin2].x, padlist[pin1].x + pitchhor, TOLERANCE) + || Equal(padlist[pin2].x + pitchhor, padlist[pin1].x, TOLERANCE); + } + } + if (!matchhor) + matcharray = false; /* no opposing pin at the correct pitch was found for every pin */ + } + } + wxASSERT(horpin_base > 0); + wxASSERT(padlist[horpin_base].startidx > 0); + for (int pin1 = 1; matcharray && pin1 <= padvalid; pin1++) { + if (padlist[pin1].startidx > 0 && Equal(padlist[pin1].y, padlist[horpin_base].y, TOLERANCE)) { + /* pin1 is in the same horizontal row as where the horizontal pitch + was detected */ + colcount++; + bool matchver = false; + for (int pin2 = 1; !matchver && pin2 <= padvalid; pin2++) { + if (pin2 != pin1 && padlist[pin2].startidx > 0 + && Equal(padlist[pin2].x, padlist[pin1].x, TOLERANCE)) { + /* pin2 is in the same vertical row as pin1, check the pitch */ + matchver = Equal(padlist[pin2].y, padlist[pin1].y + pitchver, TOLERANCE) + || Equal(padlist[pin2].y + pitchver, padlist[pin1].y, TOLERANCE); + } + } + if (!matchver) + matcharray = false; /* no opposing pin at the correct pitch was found for every pin */ + } + } + if (matcharray) { + if (colcount == 2) { + info->PadLines = 2; + info->Pitch = pitchver; + info->PitchVertical = true; + /* for pin arrays, the pin numbering is often in a zig-zag style; for + the span, this is handled here, for the pitch, it is handled later + in the routine */ + wxASSERT(horpin_base > 1 && padlist[horpin_base].startidx > 0); + for (int pinnr = horpin_base - 1; pinnr > 0; pinnr--) { + if (padlist[pinnr].startidx > 0 && Equal(padlist[pinnr].y, padlist[horpin_base].y, TOLERANCE)) { + info->SpanHor = pitchhor; + info->SpanHorPins[0] = CoordPair(padlist[pinnr].x, padlist[pinnr].y); + info->SpanHorPins[1] = CoordPair(padlist[horpin_base].x, padlist[horpin_base].y); + break; + } + } + } else if (rowcount == 2) { + info->PadLines = 2; + info->Pitch = pitchhor; + info->PitchVertical = false; + wxASSERT(verpin_base > 1 && padlist[verpin_base].startidx > 0); + for (int pinnr = verpin_base - 1; pinnr > 0; pinnr--) { + if (padlist[pinnr].startidx > 0 && Equal(padlist[pinnr].x, padlist[verpin_base].x, TOLERANCE)) { + info->SpanVer = pitchver; + info->SpanVerPins[0] = CoordPair(padlist[pinnr].x, padlist[pinnr].y); + info->SpanVerPins[1] = CoordPair(padlist[verpin_base].x, padlist[verpin_base].y); + break; + } + } + } else { + /* this is a BGA or PGA, we cannot currently edit these */ + info->PitchValid = false; + } + } else { + /* this is a quad-pack, meaning that the spans must be separately detected */ + info->PadLines = 4; /* this is a quad-pack */ + /* find horizontal span */ + wxASSERT(verpin_base > 0); + wxASSERT(padlist[verpin_base].startidx > 0); + for (int pinnr = 1; pinnr <= padvalid; pinnr++) { + if (padlist[pinnr].startidx > 0 + && Equal(padlist[pinnr].x, padlist[verpin_base].x, TOLERANCE) + && padlist[pinnr].y > padlist[verpin_base].y) + verpin_base = pinnr; + } + for (int pinnr = 1; pinnr <= padvalid; pinnr++) { + if (padlist[pinnr].startidx > 0 && pinnr != verpin_base && Equal(padlist[pinnr].y, padlist[verpin_base].y, TOLERANCE)) { + int lo = verpin_base; + int hi = pinnr; + if (padlist[lo].x > padlist[hi].x) { + hi = verpin_base; + lo = pinnr; + } + info->SpanHorPins[0] = CoordPair(padlist[lo].x, padlist[lo].y); + info->SpanHorPins[1] = CoordPair(padlist[hi].x, padlist[hi].y); + info->SpanHor = padlist[hi].x - padlist[lo].x; + wxASSERT(info->SpanHor > 0); + break; + } + } + /* find vertical span */ + wxASSERT(horpin_base > 0); + wxASSERT(padlist[horpin_base].startidx > 0); + for (int pinnr = 1; pinnr <= padvalid; pinnr++) { + if (padlist[pinnr].startidx > 0 + && Equal(padlist[pinnr].y, padlist[horpin_base].y, TOLERANCE) + && padlist[pinnr].x > padlist[verpin_base].x) + horpin_base = pinnr; + } + for (int pinnr = 1; pinnr <= padvalid; pinnr++) { + if (padlist[pinnr].startidx > 0 && pinnr != horpin_base && Equal(padlist[pinnr].x, padlist[horpin_base].x, TOLERANCE)) { + int lo = horpin_base; + int hi = pinnr; + if (padlist[lo].y > padlist[hi].y) { + hi = horpin_base; + lo = pinnr; + } + info->SpanVerPins[0] = CoordPair(padlist[lo].x, padlist[lo].y); + info->SpanVerPins[1] = CoordPair(padlist[hi].x, padlist[hi].y); + info->SpanVer = padlist[hi].y - padlist[lo].y; + wxASSERT(info->SpanVer > 0); + break; + } + } + } /* !matcharray */ + } /* pitchhor == pitchver */ + } /* more than 2 pins and 2 pitches/spans detected */ + + /* To be able to adjust the pitch, also verify the number of lines (or + rows and columns) that are "pitch-separated". If both the detected + horizontal and vertical pitch are equal, we may safely assume that + the number is 4; this was already handled. But a DIL lay-out needs + to be checked for explicitly. Fortunately this is easy: it will have + both a pitch and a span (in one direction). */ + if (info->PadLines == 1 && padvalid > 3) { + /* a 3-pin SOT23 must remain single line */ + wxASSERT(info->Pitch > EPSILON); + if (info->SpanHor > EPSILON || info->SpanVer > EPSILON) + info->PadLines = 2; + } + /* However, if the number of "regular" pads do fit in the number of lines + for these pads, clear all (to mark the pitch as "non-detected", and + therefore non-editable) */ + if (info->PadLines > 1 && info->RegPadCount % info->PadLines != 0) { + /* we do need to make an exception for 5-pin SOT23 variants */ + if (info->RegPadCount == 5 + && Equal(padlist[1].x, padlist[2].x, TOLERANCE) /* pins 1, 2 and 3 must be vertically aligned */ + && Equal(padlist[1].x, padlist[3].x, TOLERANCE) + && Equal(padlist[4].x, padlist[5].x, TOLERANCE) /* pins 4 and 5 must be vertically aligned */ + && Equal(padlist[1].y, padlist[5].y, TOLERANCE) /* pins 1 and 5 must be horizontally aligned */ + && Equal(padlist[3].y, padlist[4].y, TOLERANCE)) /* pins 2 and 4 must be horizontally aligned */ + { + info->SOT23pitch = true; /* 5-pin SOT23 */ + } else { + info->RegPadCount = 0; + info->PadLines = 0; + } + } + /* for dual-row pin arrays, the pin numbering is often in a zig-zag style */ + if (info->PadLines == 2) { + wxASSERT(info->Pitch > EPSILON); + if (info->PitchVertical) { + for (int pinnr = verpin_base - 1; pinnr > 0; pinnr--) { + if (padlist[pinnr].startidx > 0 && Equal(padlist[pinnr].x, info->PitchPins[1].GetX(), TOLERANCE)) { + info->PitchPins[0] = CoordPair(padlist[pinnr].x, padlist[pinnr].y); + info->PadSequence = verpin_base - pinnr; + break; + } + } + } else { + for (int pinnr = horpin_base - 1; pinnr > 0; pinnr--) { + if (padlist[pinnr].startidx > 0 && Equal(padlist[pinnr].y, info->PitchPins[1].GetY(), TOLERANCE)) { + info->PitchPins[0] = CoordPair(padlist[pinnr].x, padlist[pinnr].y); + info->PadSequence = horpin_base - pinnr; + break; + } + } + } + } + /* The pitch may not be edited if the footprint is not centred; so this should + be verified too */ + info->OriginCentred = true; + if (info->SpanHor > 0 && + !Equal(-info->SpanHorPins[0].GetX(), info->SpanHorPins[1].GetX())) + info->OriginCentred = false; + if (info->SpanVer > 0 && + !Equal(-info->SpanVerPins[0].GetY(), info->SpanVerPins[1].GetY())) + info->OriginCentred = false; + + /* For grid arrays (BGA/PGA), check for a centre void (because the number + for pins needs to be reduced by the pins in the centre void) */ + if (info->MtxWidth > 0 && info->MtxHeight > 0) { + int c1 = -1, r1 = -1, c2 = -1, r2 = -1; + for (int pinnr = 1; pinnr <= padvalid; pinnr++) { + if (padlist[pinnr].startidx <= 0) { + int row = (pinnr - 1) / info->MtxWidth; /* zero-based row */ + int col = pinnr - row * info->MtxWidth - 1; /* zero-based column */ + if (c1 == -1 || col < c1) + c1 = col; + if (c2 == -1 || col > c2) + c2 = col; + if (r1 == -1 || row < r1) + r1 = row; + if (r2 == -1 || row > r2) + r2 = row; + } + } + if (c1 >= 0) + info->MtxCentreX = c2 - c1 + 1; + if (r1 >= 0) + info->MtxCentreY = r2 - r1 + 1; + info->PadCount -= info->MtxCentreX * info->MtxCentreY; + } /* a special case for connectors that have a mechanical pad on each side */ if (info->RegPadCount > 0 && padsizecount[1] == 2 && padmech == 2) { @@ -5180,8 +5181,8 @@ bool TranslatePadInfo(wxArrayString* module, FootprintInfo* info) } /* copy pad outline (coordinates) into the footprint information, for ease of export */ - for (int pinnr = 1; pinnr < padcount; pinnr++) { - if (padlist[pinnr].startidx > 0) { + for (int pinnr = 1; pinnr < padcount; pinnr++) { + if (padlist[pinnr].startidx > 0) { CoordSize cs(padlist[pinnr].x - padlist[pinnr].width / 2, padlist[pinnr].y - padlist[pinnr].height / 2, padlist[pinnr].width, padlist[pinnr].height); @@ -5189,142 +5190,142 @@ bool TranslatePadInfo(wxArrayString* module, FootprintInfo* info) } } - delete[] padlist; - return true; + delete[] padlist; + return true; } /** Stores extra information on the footprint in the repository; this is used * for the on-line overview. */ bool StoreFootprintInfo(const wxString& name, const wxString& description, - const wxString& keywords, double pitch, double span, int pincount, - const wxString& imagefile) + const wxString& keywords, double pitch, double span, int pincount, + const wxString& imagefile) { - #if !defined NO_CURL - wxString params; - params = wxT("descr=") + URLEncode(description); - if (pitch > EPSILON) - params += wxT("&pitch=") + wxString::Format(wxT("%.3f"), pitch); - if (span > EPSILON) - params += wxT("&span=") + wxString::Format(wxT("%.3f"), span); - if (pincount > 0) - params += wxT("&pins=") + wxString::Format(wxT("%d"), pincount); - if (keywords.length() > 0) - params += wxT("&keywords=") + keywords; - wxString msg = curlPutInfo(name, wxT("footprints"), params, imagefile); - return (msg.length() == 0); - #else - return true; - #endif + #if !defined NO_CURL + wxString params; + params = wxT("descr=") + URLEncode(description); + if (pitch > EPSILON) + params += wxT("&pitch=") + wxString::Format(wxT("%.3f"), pitch); + if (span > EPSILON) + params += wxT("&span=") + wxString::Format(wxT("%.3f"), span); + if (pincount > 0) + params += wxT("&pins=") + wxString::Format(wxT("%d"), pincount); + if (keywords.length() > 0) + params += wxT("&keywords=") + keywords; + wxString msg = curlPutInfo(name, wxT("footprints"), params, imagefile); + return (msg.length() == 0); + #else + return true; + #endif } /** Stores extra information on the symbol in the repository; this is used * for the on-line overview. */ bool StoreSymbolInfo(const wxString& name, const wxString& description, - const wxString& keywords, const wxString& aliases, - const wxString& footprints, const wxString& imagefile) + const wxString& keywords, const wxString& aliases, + const wxString& footprints, const wxString& imagefile) { - #if !defined NO_CURL - wxString params; - params = wxT("descr=") + URLEncode(description); - if (aliases.length() > 0) - params += wxT("&alias=") + URLEncode(aliases); - if (footprints.length() > 0) - params += wxT("&fplist=") + URLEncode(footprints); - if (keywords.length() > 0) - params += wxT("&keywords=") + keywords; - wxString msg = curlPutInfo(name, wxT("symbols"), params, imagefile); - return (msg.length() == 0); - #else - return true; - #endif + #if !defined NO_CURL + wxString params; + params = wxT("descr=") + URLEncode(description); + if (aliases.length() > 0) + params += wxT("&alias=") + URLEncode(aliases); + if (footprints.length() > 0) + params += wxT("&fplist=") + URLEncode(footprints); + if (keywords.length() > 0) + params += wxT("&keywords=") + keywords; + wxString msg = curlPutInfo(name, wxT("symbols"), params, imagefile); + return (msg.length() == 0); + #else + return true; + #endif } static unsigned FindSymbolStart(const wxString& filename, const wxString& name) { - if (!wxFileExists(filename)) - return 0; /* since a library file always has a header, a symbol cannot start at line 0 */ - wxTextFile file; - if (!file.Open(filename)) - return 0; - - /* verify the header */ - wxString line = file.GetLine(0); - if (line.Left(16).CmpNoCase(wxT("EESchema-LIBRARY")) != 0 - && line.Left(13).CmpNoCase(wxT("EESchema-LIB ")) != 0) - { - file.Close(); - return 0; - } - - /* find the symbol name in the file */ - for (unsigned idx = 1; idx < file.GetLineCount(); idx++) { - line = file.GetLine(idx); - /* check for the first letter and for the complete word if that first letter - matches; this is an optimization, because the "Left" and "CmpNoCase" - methods are relatively costly (and most lines won't start with a 'D') */ - if (line[0] == wxT('D') && line.Left(4).CmpNoCase(wxT("DEF ")) == 0) { - line = line.Mid(4); - wxString symname = GetToken(&line); - /* remove leading tilde, this is an "non-visible" flag */ - if (symname[0] == wxT('~')) - symname = symname.Mid(1); - if (symname.CmpNoCase(name) == 0) { - /* found the part, now first back up a few lines up to the comments */ - while (idx > 2) { - line = file.GetLine(idx - 1); - if (line[0] != wxT('#')) - break; /* not a comment, do not include this line */ - idx -= 1; - } - return idx; - } - } - } - - return 0; /* gone through the whole file, symbol was not found */ + if (!wxFileExists(filename)) + return 0; /* since a library file always has a header, a symbol cannot start at line 0 */ + wxTextFile file; + if (!file.Open(filename)) + return 0; + + /* verify the header */ + wxString line = file.GetLine(0); + if (line.Left(16).CmpNoCase(wxT("EESchema-LIBRARY")) != 0 + && line.Left(13).CmpNoCase(wxT("EESchema-LIB ")) != 0) + { + file.Close(); + return 0; + } + + /* find the symbol name in the file */ + for (unsigned idx = 1; idx < file.GetLineCount(); idx++) { + line = file.GetLine(idx); + /* check for the first letter and for the complete word if that first letter + matches; this is an optimization, because the "Left" and "CmpNoCase" + methods are relatively costly (and most lines won't start with a 'D') */ + if (line[0] == wxT('D') && line.Left(4).CmpNoCase(wxT("DEF ")) == 0) { + line = line.Mid(4); + wxString symname = GetToken(&line); + /* remove leading tilde, this is an "non-visible" flag */ + if (symname[0] == wxT('~')) + symname = symname.Mid(1); + if (symname.CmpNoCase(name) == 0) { + /* found the part, now first back up a few lines up to the comments */ + while (idx > 2) { + line = file.GetLine(idx - 1); + if (line[0] != wxT('#')) + break; /* not a comment, do not include this line */ + idx -= 1; + } + return idx; + } + } + } + + return 0; /* gone through the whole file, symbol was not found */ } static unsigned FindSymDocStart(const wxString& filename, const wxString& name) { - if (!wxFileExists(filename)) - return 0; /* since a library file always has a header, a symbol cannot start at line 0 */ - wxTextFile file; - if (!file.Open(filename)) - return 0; - - /* verify the header */ - wxString line = file.GetLine(0); - line = line.Left(15); - if (line.CmpNoCase(wxT("EESchema-DOCLIB")) != 0) { - file.Close(); - return 0; - } - - /* find the symbol name in the file */ - for (unsigned idx = 1; idx < file.GetLineCount(); idx++) { - line = file.GetLine(idx); - /* check for the first letter and for the complete word if that first letter - matches; this is an optimization, because the "Left" and "CmpNoCase" - methods are relatively costly */ - if (line[0] == wxT('$') && line.Left(5).CmpNoCase(wxT("$CMP ")) == 0) { - line = line.Mid(5); - wxString symname = GetToken(&line); - if (symname.CmpNoCase(name) == 0) { - /* found the part, now first back up a few lines up to the comments */ - while (idx > 2) { - line = file.GetLine(idx - 1); - if (line[0] != wxT('#')) - break; /* not a comment, do not include this line */ - idx -= 1; - } - return idx; - } - } - } - - return 0; /* gone through the whole file, symbol was not found */ + if (!wxFileExists(filename)) + return 0; /* since a library file always has a header, a symbol cannot start at line 0 */ + wxTextFile file; + if (!file.Open(filename)) + return 0; + + /* verify the header */ + wxString line = file.GetLine(0); + line = line.Left(15); + if (line.CmpNoCase(wxT("EESchema-DOCLIB")) != 0) { + file.Close(); + return 0; + } + + /* find the symbol name in the file */ + for (unsigned idx = 1; idx < file.GetLineCount(); idx++) { + line = file.GetLine(idx); + /* check for the first letter and for the complete word if that first letter + matches; this is an optimization, because the "Left" and "CmpNoCase" + methods are relatively costly */ + if (line[0] == wxT('$') && line.Left(5).CmpNoCase(wxT("$CMP ")) == 0) { + line = line.Mid(5); + wxString symname = GetToken(&line); + if (symname.CmpNoCase(name) == 0) { + /* found the part, now first back up a few lines up to the comments */ + while (idx > 2) { + line = file.GetLine(idx - 1); + if (line[0] != wxT('#')) + break; /* not a comment, do not include this line */ + idx -= 1; + } + return idx; + } + } + } + + return 0; /* gone through the whole file, symbol was not found */ } /** ExistSymbol() checks wether the symbol is present in the library. The @@ -5334,340 +5335,340 @@ static unsigned FindSymDocStart(const wxString& filename, const wxString& name) */ bool ExistSymbol(const wxString& filename, const wxString& name, const wxString& author) { - if (filename.CmpNoCase(LIB_REPOS) == 0) { - #if defined NO_CURL - return false; - #else - wxString msg = curlGet(name, author, wxT("symbols"), 0); - return msg.length() == 0; - #endif - } else { - unsigned start = FindSymbolStart(filename, name); - return start > 0; - } + if (filename.CmpNoCase(LIB_REPOS) == 0) { + #if defined NO_CURL + return false; + #else + wxString msg = curlGet(name, author, wxT("symbols"), 0); + return msg.length() == 0; + #endif + } else { + unsigned start = FindSymbolStart(filename, name); + return start > 0; + } } bool InsertSymbol(const wxString& filename, const wxString& name, const wxArrayString& symbol) { - if (filename.CmpNoCase(LIB_REPOS) == 0) { - #if defined NO_CURL - return false; - #else - wxString msg = curlPut(name, wxT("symbols"), symbol); - return msg.length() == 0; - #endif - } else { - wxTextFile file; - if (!file.Open(filename)) - return false; - - /* verify the header */ - wxString line = file.GetLine(0); - if (line.Left(16).CmpNoCase(wxT("EESchema-LIBRARY")) != 0) { - file.Close(); - return false; - } - - /* find the insertion point */ - unsigned insertionpoint = 1; - if (file.GetLineCount() > insertionpoint) { - line = file.GetLine(insertionpoint); - if (line.Left(9).CmpNoCase(wxT("#encoding")) == 0) - insertionpoint += 1; - } - for (unsigned idx = insertionpoint; idx < file.GetLineCount(); idx++) { - line = file.GetLine(idx); - if (line[0] == wxT('D') && line.Left(4).CmpNoCase(wxT("DEF ")) == 0) { - line = line.Mid(4); - wxString symname = GetToken(&line); - /* remove leading tilde, this is an "non-visible" flag */ - if (symname[0] == wxT('~')) - symname = symname.Mid(1); - int result = symname.CmpNoCase(name); - if (result < 0) { - insertionpoint = idx; - } else if (result > 0) { - break; - } else { - /* found a symbol with the same name; this should not occur */ - wxASSERT(false); - file.Close(); - return false; - } + if (filename.CmpNoCase(LIB_REPOS) == 0) { + #if defined NO_CURL + return false; + #else + wxString msg = curlPut(name, wxT("symbols"), symbol); + return msg.length() == 0; + #endif + } else { + wxTextFile file; + if (!file.Open(filename)) + return false; + + /* verify the header */ + wxString line = file.GetLine(0); + if (line.Left(16).CmpNoCase(wxT("EESchema-LIBRARY")) != 0) { + file.Close(); + return false; + } + + /* find the insertion point */ + unsigned insertionpoint = 1; + if (file.GetLineCount() > insertionpoint) { + line = file.GetLine(insertionpoint); + if (line.Left(9).CmpNoCase(wxT("#encoding")) == 0) + insertionpoint += 1; + } + for (unsigned idx = insertionpoint; idx < file.GetLineCount(); idx++) { + line = file.GetLine(idx); + if (line[0] == wxT('D') && line.Left(4).CmpNoCase(wxT("DEF ")) == 0) { + line = line.Mid(4); + wxString symname = GetToken(&line); + /* remove leading tilde, this is an "non-visible" flag */ + if (symname[0] == wxT('~')) + symname = symname.Mid(1); + int result = symname.CmpNoCase(name); + if (result < 0) { + insertionpoint = idx; + } else if (result > 0) { + break; + } else { + /* found a symbol with the same name; this should not occur */ + wxASSERT(false); + file.Close(); + return false; + } } else if (line[0] == wxT('#') && line.CmpNoCase(wxT("#End Library")) == 0) { /* if not yet broken out of the loop, the symbol must be at the end of the list */ insertionpoint = idx; - } - } - /* move the insertion point up to above the comment (there usually is one) */ - while (insertionpoint > 2) { - line = file.GetLine(insertionpoint - 1); - if (line[0] != wxT('#')) - break; /* not a comment, do not include this line */ - insertionpoint -= 1; - } - /* insert the symbol */ - unsigned linenr = 0; - while (linenr < symbol.Count()) { + } + } + /* move the insertion point up to above the comment (there usually is one) */ + while (insertionpoint > 2) { + line = file.GetLine(insertionpoint - 1); + if (line[0] != wxT('#')) + break; /* not a comment, do not include this line */ + insertionpoint -= 1; + } + /* insert the symbol */ + unsigned linenr = 0; + while (linenr < symbol.Count()) { wxString tmp = symbol[linenr]; - file.InsertLine(tmp, insertionpoint + linenr); - linenr += 1; - if (tmp.CmpNoCase(wxT("ENDDEF")) == 0) - break; - } - file.Write(); - file.Close(); - - /* write the remainder in the documentation file */ - if (linenr < symbol.Count()) { - wxFileName fname(filename); - fname.SetExt(wxT("dcm")); - if (wxFileExists(fname.GetFullPath())) { - file.Open(fname.GetFullPath()); - } else { - /* create the DCM file if none exists */ - if (!file.Create(fname.GetFullPath())) - return true; - file.InsertLine(wxT("EESchema-DOCLIB Version 2.0 Date: ") + wxNow(), 0); - file.InsertLine(wxT("#"), 1); - file.InsertLine(wxT("#End Library"), 2); - } - /* again, find the insertion point */ - insertionpoint = 1; - for (unsigned idx = 1; idx < file.GetLineCount(); idx++) { - line = file.GetLine(idx); - if (line[0] == wxT('$') && line.Left(5).CmpNoCase(wxT("$CMP ")) == 0) { - line = line.Mid(5); - wxString symname = GetToken(&line); - int result = symname.CmpNoCase(name); - if (result < 0) { - insertionpoint = idx; - } else if (result > 0) { - break; - } else { - /* found a symbol with the same name; this should not occur */ - wxASSERT(false); - file.Close(); - return false; - } + file.InsertLine(tmp, insertionpoint + linenr); + linenr += 1; + if (tmp.CmpNoCase(wxT("ENDDEF")) == 0) + break; + } + file.Write(); + file.Close(); + + /* write the remainder in the documentation file */ + if (linenr < symbol.Count()) { + wxFileName fname(filename); + fname.SetExt(wxT("dcm")); + if (wxFileExists(fname.GetFullPath())) { + file.Open(fname.GetFullPath()); + } else { + /* create the DCM file if none exists */ + if (!file.Create(fname.GetFullPath())) + return true; + file.InsertLine(wxT("EESchema-DOCLIB Version 2.0 Date: ") + wxNow(), 0); + file.InsertLine(wxT("#"), 1); + file.InsertLine(wxT("#End Library"), 2); + } + /* again, find the insertion point */ + insertionpoint = 1; + for (unsigned idx = 1; idx < file.GetLineCount(); idx++) { + line = file.GetLine(idx); + if (line[0] == wxT('$') && line.Left(5).CmpNoCase(wxT("$CMP ")) == 0) { + line = line.Mid(5); + wxString symname = GetToken(&line); + int result = symname.CmpNoCase(name); + if (result < 0) { + insertionpoint = idx; + } else if (result > 0) { + break; + } else { + /* found a symbol with the same name; this should not occur */ + wxASSERT(false); + file.Close(); + return false; + } } else if (line[0] == wxT('#') && line.CmpNoCase(wxT("#End Library")) == 0) { /* if not yet broken out of the loop, the symbol must be at the end of the list */ insertionpoint = idx; } - } - /* move the insertion point up to above the comment (there usually is one) */ - while (insertionpoint > 1) { - line = file.GetLine(insertionpoint - 1); - if (line[0] != wxT('#')) - break; /* not a comment, do not include this line */ - insertionpoint -= 1; - } - /* insert the symbol */ - unsigned dcmline = 0; - while (linenr < symbol.Count()) { - file.InsertLine(symbol[linenr], insertionpoint + dcmline); - linenr += 1; - dcmline += 1; - } - file.Write(); - file.Close(); - } - return true; - } + } + /* move the insertion point up to above the comment (there usually is one) */ + while (insertionpoint > 1) { + line = file.GetLine(insertionpoint - 1); + if (line[0] != wxT('#')) + break; /* not a comment, do not include this line */ + insertionpoint -= 1; + } + /* insert the symbol */ + unsigned dcmline = 0; + while (linenr < symbol.Count()) { + file.InsertLine(symbol[linenr], insertionpoint + dcmline); + linenr += 1; + dcmline += 1; + } + file.Write(); + file.Close(); + } + return true; + } } bool RemoveSymbol(const wxString& filename, const wxString& name) { - if (filename.CmpNoCase(LIB_REPOS) == 0) { - #if defined NO_CURL - return false; - #else - wxString msg = curlDelete(name, wxT("symbols")); - return msg.length() == 0; - #endif - } else { - unsigned start = FindSymbolStart(filename, name); - if (start == 0) - return false; - wxTextFile file; - wxCHECK(file.Open(filename), false); - - /* delete everything up to (and including) the "ENDDEF" */ - while (start < file.GetLineCount()) { - wxString line = file.GetLine(start); - file.RemoveLine(start); - if (line.CmpNoCase(wxT("ENDDEF")) == 0) - break; - } - file.Write(); - file.Close(); - - /* now go through the documentation file to rename the symbol - first replace the extension of the input library file */ - wxFileName fname(filename); - fname.SetExt(wxT("dcm")); - start = FindSymDocStart(fname.GetFullPath(), name); - if (start > 0) { - wxCHECK(file.Open(fname.GetFullPath()), false); - while (start < file.GetLineCount()) { - wxString line = file.GetLine(start); - file.RemoveLine(start); - if (line.CmpNoCase(wxT("$ENDCMP")) == 0) - break; - } - file.Write(); - file.Close(); - } - - return true; - } + if (filename.CmpNoCase(LIB_REPOS) == 0) { + #if defined NO_CURL + return false; + #else + wxString msg = curlDelete(name, wxT("symbols")); + return msg.length() == 0; + #endif + } else { + unsigned start = FindSymbolStart(filename, name); + if (start == 0) + return false; + wxTextFile file; + wxCHECK(file.Open(filename), false); + + /* delete everything up to (and including) the "ENDDEF" */ + while (start < file.GetLineCount()) { + wxString line = file.GetLine(start); + file.RemoveLine(start); + if (line.CmpNoCase(wxT("ENDDEF")) == 0) + break; + } + file.Write(); + file.Close(); + + /* now go through the documentation file to rename the symbol + first replace the extension of the input library file */ + wxFileName fname(filename); + fname.SetExt(wxT("dcm")); + start = FindSymDocStart(fname.GetFullPath(), name); + if (start > 0) { + wxCHECK(file.Open(fname.GetFullPath()), false); + while (start < file.GetLineCount()) { + wxString line = file.GetLine(start); + file.RemoveLine(start); + if (line.CmpNoCase(wxT("$ENDCMP")) == 0) + break; + } + file.Write(); + file.Close(); + } + + return true; + } } bool RenameSymbol(wxArrayString* symbol, const wxString& oldname, const wxString& newname) { - for (int idx = 0; idx < (int)symbol->Count(); idx++) { - wxString line = (*symbol)[idx]; - if (line[0] == wxT('#') && line.Find(oldname) > 0) { - (*symbol)[idx] = wxT("# ") + newname; - } else if (line.Left(4).CmpNoCase(wxT("DEF ")) == 0 - || line.Left(3).CmpNoCase(wxT("F1 ")) == 0) - { - (*symbol)[idx].Replace(oldname, newname); - } - } - return true; + for (int idx = 0; idx < (int)symbol->Count(); idx++) { + wxString line = (*symbol)[idx]; + if (line[0] == wxT('#') && line.Find(oldname) > 0) { + (*symbol)[idx] = wxT("# ") + newname; + } else if (line.Left(4).CmpNoCase(wxT("DEF ")) == 0 + || line.Left(3).CmpNoCase(wxT("F1 ")) == 0) + { + (*symbol)[idx].Replace(oldname, newname); + } + } + return true; } bool RenameSymbol(const wxString& filename, const wxString& oldname, const wxString& newname) { - if (filename.CmpNoCase(LIB_REPOS) == 0) { - #if defined NO_CURL - return false; - #else - wxArrayString module; - wxString msg = curlGet(oldname, wxEmptyString, wxT("symbols"), &module); - if (msg.length() > 0) - return false; - RenameFootprint(&module, oldname, newname); - msg = curlPut(newname, wxT("symbols"), module); - if (msg.length() > 0) - return false; - msg = curlDelete(oldname, wxT("symbols")); - return msg.length() == 0; - #endif - } else { - unsigned start = FindSymbolStart(filename, oldname); - if (start == 0) - return false; - wxTextFile file; - wxCHECK(file.Open(filename), false); - - /* include everything up to the "ENDDEF" */ - for (unsigned idx = start; idx < file.GetLineCount(); idx++) { - wxString line = file.GetLine(idx); - bool replace = false; - if (line.CmpNoCase(wxT("ENDDEF")) == 0) - break; - if (line[0] == wxT('#') && line.Find(oldname) > 0) { - line = wxT("# ") + newname; - replace = true; - } else if (line.Left(4).CmpNoCase(wxT("DEF ")) == 0 - || line.Left(3).CmpNoCase(wxT("F1 ")) == 0) - { - line.Replace(oldname, newname); - replace = true; - } - if (replace) { - file.RemoveLine(idx); - file.InsertLine(line, idx); - } - } - file.Write(); - file.Close(); - - /* now go through the documentation file to rename the symbol - first replace the extension of the input library file */ - wxFileName fname(filename); - fname.SetExt(wxT("dcm")); - start = FindSymDocStart(fname.GetFullPath(), oldname); - if (start > 0) { - wxCHECK(file.Open(fname.GetFullPath()), false); - for (unsigned idx = start; idx < file.GetLineCount(); idx++) { - wxString line = file.GetLine(idx); - if (line.CmpNoCase(wxT("$ENDCMP")) == 0) - break; - if (line.Left(5).CmpNoCase(wxT("$CMP ")) == 0) { - line = wxT("$CMP ") + newname; - file.RemoveLine(idx); - file.InsertLine(line, idx); - } - } - file.Write(); - file.Close(); - } - - return true; - } + if (filename.CmpNoCase(LIB_REPOS) == 0) { + #if defined NO_CURL + return false; + #else + wxArrayString module; + wxString msg = curlGet(oldname, wxEmptyString, wxT("symbols"), &module); + if (msg.length() > 0) + return false; + RenameFootprint(&module, oldname, newname); + msg = curlPut(newname, wxT("symbols"), module); + if (msg.length() > 0) + return false; + msg = curlDelete(oldname, wxT("symbols")); + return msg.length() == 0; + #endif + } else { + unsigned start = FindSymbolStart(filename, oldname); + if (start == 0) + return false; + wxTextFile file; + wxCHECK(file.Open(filename), false); + + /* include everything up to the "ENDDEF" */ + for (unsigned idx = start; idx < file.GetLineCount(); idx++) { + wxString line = file.GetLine(idx); + bool replace = false; + if (line.CmpNoCase(wxT("ENDDEF")) == 0) + break; + if (line[0] == wxT('#') && line.Find(oldname) > 0) { + line = wxT("# ") + newname; + replace = true; + } else if (line.Left(4).CmpNoCase(wxT("DEF ")) == 0 + || line.Left(3).CmpNoCase(wxT("F1 ")) == 0) + { + line.Replace(oldname, newname); + replace = true; + } + if (replace) { + file.RemoveLine(idx); + file.InsertLine(line, idx); + } + } + file.Write(); + file.Close(); + + /* now go through the documentation file to rename the symbol + first replace the extension of the input library file */ + wxFileName fname(filename); + fname.SetExt(wxT("dcm")); + start = FindSymDocStart(fname.GetFullPath(), oldname); + if (start > 0) { + wxCHECK(file.Open(fname.GetFullPath()), false); + for (unsigned idx = start; idx < file.GetLineCount(); idx++) { + wxString line = file.GetLine(idx); + if (line.CmpNoCase(wxT("$ENDCMP")) == 0) + break; + if (line.Left(5).CmpNoCase(wxT("$CMP ")) == 0) { + line = wxT("$CMP ") + newname; + file.RemoveLine(idx); + file.InsertLine(line, idx); + } + } + file.Write(); + file.Close(); + } + + return true; + } } /** LoadSymbol() - * \param filename The name of the library, or the repository string - * \param name The symbol name - * \param author The name of the author of the symbol; only used for the repository - * \param striplink If true, the link to the template is stripped from the - * symbol - * \param symbol The array that will hold the symbol data on output + * \param filename The name of the library, or the repository string + * \param name The symbol name + * \param author The name of the author of the symbol; only used for the repository + * \param striplink If true, the link to the template is stripped from the + * symbol + * \param symbol The array that will hold the symbol data on output */ bool LoadSymbol(const wxString& filename, const wxString& name, const wxString& author, - bool striplink, wxArrayString* symbol) + bool striplink, wxArrayString* symbol) { - wxASSERT(symbol != NULL); - symbol->Clear(); - - if (filename.CmpNoCase(LIB_REPOS) == 0) { - #if defined NO_CURL - return false; - #else - wxString msg = curlGet(name, author, wxT("symbols"), symbol); - return msg.length() == 0; - #endif - } else { - unsigned start = FindSymbolStart(filename, name); - if (start == 0) - return false; - wxTextFile file; - wxCHECK(file.Open(filename), false); - - /* include everything up to the "ENDDEF", except (perhaps) "F4" */ - for (unsigned idx = start; idx < file.GetLineCount(); idx++) { - wxString line = file.GetLine(idx); - line.Trim(); - line.Trim(false); - if (!striplink || line.Left(3).Cmp(wxT("F4 ")) != 0) - symbol->Add(line); - if (line.Cmp(wxT("ENDDEF")) == 0) - break; - } - file.Close(); - - /* also load the description and keywords from the documentation file; these - are simply appended to the symbol definition */ - wxFileName fname(filename); - fname.SetExt(wxT("dcm")); - start = FindSymDocStart(fname.GetFullPath(), name); - if (start > 0) { - wxCHECK(file.Open(fname.GetFullPath()), false); - for (unsigned idx = start; idx < file.GetLineCount(); idx++) { - wxString line = file.GetLine(idx); - line.Trim(); - line.Trim(false); - symbol->Add(line); - if (line.CmpNoCase(wxT("$ENDCMP")) == 0) - break; - } - file.Close(); - } - - return true; - } + wxASSERT(symbol != NULL); + symbol->Clear(); + + if (filename.CmpNoCase(LIB_REPOS) == 0) { + #if defined NO_CURL + return false; + #else + wxString msg = curlGet(name, author, wxT("symbols"), symbol); + return msg.length() == 0; + #endif + } else { + unsigned start = FindSymbolStart(filename, name); + if (start == 0) + return false; + wxTextFile file; + wxCHECK(file.Open(filename), false); + + /* include everything up to the "ENDDEF", except (perhaps) "F4" */ + for (unsigned idx = start; idx < file.GetLineCount(); idx++) { + wxString line = file.GetLine(idx); + line.Trim(); + line.Trim(false); + if (!striplink || line.Left(3).Cmp(wxT("F4 ")) != 0) + symbol->Add(line); + if (line.Cmp(wxT("ENDDEF")) == 0) + break; + } + file.Close(); + + /* also load the description and keywords from the documentation file; these + are simply appended to the symbol definition */ + wxFileName fname(filename); + fname.SetExt(wxT("dcm")); + start = FindSymDocStart(fname.GetFullPath(), name); + if (start > 0) { + wxCHECK(file.Open(fname.GetFullPath()), false); + for (unsigned idx = start; idx < file.GetLineCount(); idx++) { + wxString line = file.GetLine(idx); + line.Trim(); + line.Trim(false); + symbol->Add(line); + if (line.CmpNoCase(wxT("$ENDCMP")) == 0) + break; + } + file.Close(); + } + + return true; + } } diff --git a/src/libraryfunctions.h b/src/libraryfunctions.h index 1548a3e..0cd2f1e 100644 --- a/src/libraryfunctions.h +++ b/src/libraryfunctions.h @@ -16,7 +16,7 @@ * License for the specific language governing permissions and limitations * under the License. * - * $Id: libraryfunctions.h 5685 2017-05-23 10:35:40Z thiadmer $ + * $Id: libraryfunctions.h 5686 2017-05-24 13:56:46Z thiadmer $ */ #ifndef LIBRARYFUNCTIONS_H #define LIBRARYFUNCTIONS_H @@ -92,7 +92,7 @@ class CoordSize { bool OverlapOrTouch(const CoordSize& cs) const { return GetLeft() < cs.GetRight() + EPSILON && GetRight() > cs.GetLeft() - EPSILON - && GetTop() < cs.GetBottom() + EPSILON && GetBottom() < cs.GetTop() - EPSILON; + && GetTop() < cs.GetBottom() + EPSILON && GetBottom() > cs.GetTop() - EPSILON; } void Union(const CoordSize& cs) { if (cs.GetLeft() < m_x) diff --git a/src/svnrev.h b/src/svnrev.h index 82ca8ab..41eb2bf 100644 --- a/src/svnrev.h +++ b/src/svnrev.h @@ -2,17 +2,17 @@ * (http://www.compuphase.com/svnrev.htm). * You should not modify it manually, as it may be re-generated. * - * $Revision: 5593$ - * $Date: 2016-11-01$ + * $Revision: 5685M$ + * $Date: 2017-05-23$ */ #ifndef SVN_REV_H #define SVN_REV_H -#define SVN_REV 5593 -#define SVN_REVSTR "5593" -#define SVN_REVDATE "2016-11-01" -#define SVN_REVSTAMP 20161101L +#define SVN_REV 5685 +#define SVN_REVSTR "1.3.5685" +#define SVN_REVDATE "2017-05-23" +#define SVN_REVSTAMP 20170523L #define SVN_REVMODIFIED 0 #endif /* SVN_REV_H */ diff --git a/template/QFPX.mt b/template/QFPX.mt index 4aa4745..31c5ce3 100644 --- a/template/QFPX.mt +++ b/template/QFPX.mt @@ -4,7 +4,7 @@ #pins 25 29 ... #flags aux-pad(flag,*) rebuild #param 33 @PT 0.8 @PP 8.5 @SH 8.5 @SV 1.3 @PW 0.45 @PL 5 @PLA 5 @PWA \ -5# 6.8 @BW 6.8 @BL 0.2 @BP 0.65 @TS 15 @TW 0.2 @STP 20 @PSRA 1.5 @EPDOT +5# 6.8 @BW 6.8 @BL 0.2 @BP 0.65 @TS 15 @TW 0.2 @STP 25 @PSRA 1.5 @EPDOT #model QFP $MODULE {NAME} AR QFPX