Extract set-connector-type into core; add it to the wx GUI.

First of the editing ops to reach the wx frontend. Extract the business logic
(validate the kind, tag the part, apply the connector model) into
core/app/edit.{hpp,cpp}: app::set_connector_type(Part*, kind) -> {ok, error,
materialised}, refusing without mutation when the kind is invalid for the part.

Both TUI call sites now use it: the `set-connector-type` command and the
interactive settype screen (de-dup) — output unchanged. The wx GUI gains an
Edit ▸ Set connector type… menu: a reusable PickPart() (module → part choice
dialogs) + a kind prompt, then the same core op, logged and reflected in the
model tree. Prune the now-dead pin_model/transform_vpx includes from
commands.cpp.

Unit-tested by tests/test_edit.cpp (free-form kind tags; invalid kind refused
without mutation; null part). tui + wx build clean; 376 core assertions green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-03 21:13:08 +02:00
parent 76807b0307
commit 7e88f82446
7 changed files with 175 additions and 18 deletions

View File

@@ -2,6 +2,7 @@
#include "frontends/wx/wx_frontend.hpp"
#include "core/app/edit.hpp"
#include "core/app/export.hpp"
#include "core/app/load.hpp"
#include "core/app/verify.hpp"
@@ -31,6 +32,7 @@ enum {
ID_RESTORE,
ID_SAVE,
ID_EXPORT,
ID_SET_CONNECTOR_TYPE,
ID_VERIFY,
ID_QUIT,
ID_ABOUT,
@@ -53,6 +55,9 @@ EssimFrame::EssimFrame(WxFrontend &fe)
file->AppendSeparator();
file->Append(ID_QUIT, "&Quit\tCtrl-Q");
auto *edit = new wxMenu;
edit->Append(ID_SET_CONNECTOR_TYPE, "Set &connector type…\tCtrl-T");
auto *sysm = new wxMenu;
sysm->Append(ID_VERIFY, "&Verify\tCtrl-K");
@@ -61,6 +66,7 @@ EssimFrame::EssimFrame(WxFrontend &fe)
auto *bar = new wxMenuBar;
bar->Append(file, "&File");
bar->Append(edit, "&Edit");
bar->Append(sysm, "&System");
bar->Append(help, "&Help");
SetMenuBar(bar);
@@ -93,6 +99,7 @@ EssimFrame::EssimFrame(WxFrontend &fe)
Bind(wxEVT_MENU, &EssimFrame::OnRestore, this, ID_RESTORE);
Bind(wxEVT_MENU, &EssimFrame::OnSave, this, ID_SAVE);
Bind(wxEVT_MENU, &EssimFrame::OnExport, this, ID_EXPORT);
Bind(wxEVT_MENU, &EssimFrame::OnSetConnectorType, this, ID_SET_CONNECTOR_TYPE);
Bind(wxEVT_MENU, &EssimFrame::OnVerify, this, ID_VERIFY);
Bind(wxEVT_MENU, &EssimFrame::OnQuit, this, ID_QUIT);
Bind(wxEVT_MENU, &EssimFrame::OnAbout, this, ID_ABOUT);
@@ -246,6 +253,62 @@ void EssimFrame::OnExport(wxCommandEvent &) {
}
}
Part *EssimFrame::PickPart() {
System *sys = fe_.system();
if (!sys || sys->modules()->size() == 0) {
wxMessageBox("No modules loaded.", "Select part",
wxOK | wxICON_INFORMATION, this);
return nullptr;
}
std::vector<std::string> mods;
for (auto &mkv : *sys->modules()) mods.push_back(mkv.first);
std::sort(mods.begin(), mods.end());
wxArrayString mchoices;
for (const auto &m : mods) mchoices.Add(wx(m));
int mi = wxGetSingleChoiceIndex("Module:", "Select part", mchoices, this);
if (mi < 0) return nullptr;
Module *m = sys->modules()->get(mods[mi]);
if (m->size() == 0) {
wxMessageBox("That module has no parts.", "Select part",
wxOK | wxICON_INFORMATION, this);
return nullptr;
}
std::vector<std::string> parts;
for (auto &pkv : *m) parts.push_back(pkv.first);
std::sort(parts.begin(), parts.end());
wxArrayString pchoices;
for (const auto &p : parts) pchoices.Add(wx(p));
int pi = wxGetSingleChoiceIndex("Part:", "Select part", pchoices, this);
if (pi < 0) return nullptr;
return m->get(parts[pi]);
}
void EssimFrame::OnSetConnectorType(wxCommandEvent &) {
Part *p = PickPart();
if (!p) return;
wxTextEntryDialog dlg(this, "Connector type (empty = none):",
"Set connector type", wx(p->connector_type));
if (dlg.ShowModal() != wxID_OK) return;
const std::string kind = dlg.GetValue().utf8_string();
app::SetConnectorTypeResult r = app::set_connector_type(p, kind);
if (!r.ok) {
Log("set-connector-type refused: " + wx(r.error));
wxMessageBox(wx(r.error), "Refused", wxOK | wxICON_ERROR, this);
return;
}
wxString who = (p->prnt ? wx(p->prnt->name) + "/" : wxString()) + wx(p->name);
Log(who + ": connector_type = " + (kind.empty() ? wxString("(none)") : wx(kind)));
if (r.materialised > 0)
Log(wxString::Format(" added %d NC pin(s) from the connector layout",
r.materialised));
RebuildModelView();
}
void EssimFrame::OnVerify(wxCommandEvent &) {
app::VerifyReport r = app::verify(fe_.system());