wx: add Connect parts to the Edit menu

Third editing op in the wx GUI. No core change — app::connect_parts was already
extracted and unit-tested; this is pure wiring. Edit ▸ Connect parts… picks two
parts (PickPart twice, now caption-parameterised to label "first/second part"),
derives their parent modules from Part::prnt, calls app::connect_parts and
renders the same outcomes the TUI does: refused / identity NC fill / connected
(N wires) / failed.

wx builds clean, window opens with no asserts; tui + tests unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-03 21:21:49 +02:00
parent b999446151
commit fc3ef333fa
2 changed files with 51 additions and 7 deletions

View File

@@ -2,6 +2,7 @@
#include "frontends/wx/wx_frontend.hpp"
#include "core/app/connect.hpp"
#include "core/app/edit.hpp"
#include "core/app/export.hpp"
#include "core/app/load.hpp"
@@ -34,6 +35,7 @@ enum {
ID_EXPORT,
ID_SET_CONNECTOR_TYPE,
ID_ATTACH_BSDL,
ID_CONNECT,
ID_VERIFY,
ID_QUIT,
ID_ABOUT,
@@ -59,6 +61,8 @@ EssimFrame::EssimFrame(WxFrontend &fe)
auto *edit = new wxMenu;
edit->Append(ID_SET_CONNECTOR_TYPE, "Set &connector type…\tCtrl-T");
edit->Append(ID_ATTACH_BSDL, "Attach &BSDL…\tCtrl-B");
edit->AppendSeparator();
edit->Append(ID_CONNECT, "C&onnect parts…\tCtrl-O");
auto *sysm = new wxMenu;
sysm->Append(ID_VERIFY, "&Verify\tCtrl-K");
@@ -103,6 +107,7 @@ EssimFrame::EssimFrame(WxFrontend &fe)
Bind(wxEVT_MENU, &EssimFrame::OnExport, this, ID_EXPORT);
Bind(wxEVT_MENU, &EssimFrame::OnSetConnectorType, this, ID_SET_CONNECTOR_TYPE);
Bind(wxEVT_MENU, &EssimFrame::OnAttachBsdl, this, ID_ATTACH_BSDL);
Bind(wxEVT_MENU, &EssimFrame::OnConnect, this, ID_CONNECT);
Bind(wxEVT_MENU, &EssimFrame::OnVerify, this, ID_VERIFY);
Bind(wxEVT_MENU, &EssimFrame::OnQuit, this, ID_QUIT);
Bind(wxEVT_MENU, &EssimFrame::OnAbout, this, ID_ABOUT);
@@ -256,10 +261,10 @@ void EssimFrame::OnExport(wxCommandEvent &) {
}
}
Part *EssimFrame::PickPart() {
Part *EssimFrame::PickPart(const wxString &caption) {
System *sys = fe_.system();
if (!sys || sys->modules()->size() == 0) {
wxMessageBox("No modules loaded.", "Select part",
wxMessageBox("No modules loaded.", caption,
wxOK | wxICON_INFORMATION, this);
return nullptr;
}
@@ -269,12 +274,12 @@ Part *EssimFrame::PickPart() {
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);
int mi = wxGetSingleChoiceIndex("Module:", caption, 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",
wxMessageBox("That module has no parts.", caption,
wxOK | wxICON_INFORMATION, this);
return nullptr;
}
@@ -283,7 +288,7 @@ Part *EssimFrame::PickPart() {
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);
int pi = wxGetSingleChoiceIndex("Part:", caption, pchoices, this);
if (pi < 0) return nullptr;
return m->get(parts[pi]);
}
@@ -336,6 +341,43 @@ void EssimFrame::OnAttachBsdl(wxCommandEvent &) {
RebuildModelView();
}
void EssimFrame::OnConnect(wxCommandEvent &) {
Part *p1 = PickPart("Connect — first part");
if (!p1) return;
Part *p2 = PickPart("Connect — second part");
if (!p2) return;
if (p1 == p2) {
wxMessageBox("Pick two different parts.", "Connect",
wxOK | wxICON_INFORMATION, this);
return;
}
// m1/m2 are the parts' parent modules — connect_parts needs them for the
// Connection name and ownership.
app::ConnectResult r =
app::connect_parts(fe_.system(), p1->prnt, p1, p2->prnt, p2);
if (r.refused) {
Log("connect refused: " + wx(r.error));
wxMessageBox(wx(r.error), "Connect refused", wxOK | wxICON_ERROR, this);
return;
}
if (!r.identity_info.empty()) {
Log("connect: " + wx(r.identity_info));
if (r.nc_added > 0)
Log(wxString::Format("connect: added %d NC pin(s) so both sides match",
r.nc_added));
}
if (r.ok) {
Log(wxString::Format("connected: %s via %s (%d wires)",
wx(r.connection_name), wx(r.transform_name), r.wires));
} else {
Log("connect failed: " + wx(r.error));
wxMessageBox(wx(r.error), "Connect failed", wxOK | wxICON_ERROR, this);
}
RebuildModelView();
}
void EssimFrame::OnVerify(wxCommandEvent &) {
app::VerifyReport r = app::verify(fe_.system());

View File

@@ -24,13 +24,15 @@ private:
void OnExport(wxCommandEvent &);
void OnSetConnectorType(wxCommandEvent &);
void OnAttachBsdl(wxCommandEvent &);
void OnConnect(wxCommandEvent &);
void OnVerify(wxCommandEvent &);
void OnQuit(wxCommandEvent &);
void OnAbout(wxCommandEvent &);
// Prompt the user to pick a module then a part from the current System.
// Returns nullptr if there is nothing to pick or the user cancels.
class Part *PickPart();
// `caption` titles the dialogs (e.g. to distinguish two picks). Returns
// nullptr if there is nothing to pick or the user cancels.
class Part *PickPart(const wxString &caption = "Select part");
void RebuildModelView(); ///< refresh tree + overview from the System
void Log(const wxString &line); ///< append a line to the log pane