From fc3ef333fa2f4c8eae71efd7ba217d3ae4010f8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Wed, 3 Jun 2026 21:21:49 +0200 Subject: [PATCH] wx: add Connect parts to the Edit menu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/frontends/wx/wx_frame.cpp | 52 +++++++++++++++++++++++++++++++---- src/frontends/wx/wx_frame.hpp | 6 ++-- 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/frontends/wx/wx_frame.cpp b/src/frontends/wx/wx_frame.cpp index 2f89124..732ef1a 100644 --- a/src/frontends/wx/wx_frame.cpp +++ b/src/frontends/wx/wx_frame.cpp @@ -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()); diff --git a/src/frontends/wx/wx_frame.hpp b/src/frontends/wx/wx_frame.hpp index ff82a61..4c9f14e 100644 --- a/src/frontends/wx/wx_frame.hpp +++ b/src/frontends/wx/wx_frame.hpp @@ -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