--- nono/wx/wxmainframe.cpp 2026/04/29 17:05:23 1.1.1.17 +++ nono/wx/wxmainframe.cpp 2026/04/29 17:05:44 1.1.1.22 @@ -10,6 +10,7 @@ #include "wxmainframe.h" #include "fontmanager.h" +#include "wxaccstatmonitor.h" #include "wxdipswwindow.h" #include "wxdumpmonitor.h" #include "wxlcdwindow.h" @@ -28,11 +29,15 @@ #include "config.h" #include "fdc.h" #include "fdd.h" +#include "hostcom.h" +#include "hostnet.h" #include "mainapp.h" #include "mpu.h" +#include "netdriver_slirp.h" #include "nmi.h" #include "power.h" -#include "spc.h" +#include "scsidev.h" +#include "scsidomain.h" #include "syncer.h" #include @@ -80,6 +85,44 @@ enum { ID_INPUT_JP, ID_INPUT_END, + ID_HOSTNET0_START, + ID_HOSTNET0_USERMODE, + ID_HOSTNET0_TAP, + ID_HOSTNET0_BPF, + ID_HOSTNET0_AFPACKET, + ID_HOSTNET0_NONE, // 最後に置くこと + + ID_HOSTNET1_START, + ID_HOSTNET1_USERMODE, + ID_HOSTNET1_TAP, + ID_HOSTNET1_BPF, + ID_HOSTNET1_AFPACKET, + ID_HOSTNET1_NONE, // 最後に置くこと + + ID_HOSTCOM0_START, + ID_HOSTCOM0_TCP, + ID_HOSTCOM0_STDIO, + ID_HOSTCOM0_CONSOLE, + ID_HOSTCOM0_NONE, // 最後に置くこと + + ID_HOSTCOM1_START, + ID_HOSTCOM1_TCP, + ID_HOSTCOM1_STDIO, + ID_HOSTCOM1_CONSOLE, + ID_HOSTCOM1_NONE, // 最後に置くこと + + ID_HOSTCOM2_START, + ID_HOSTCOM2_TCP, + ID_HOSTCOM2_STDIO, + ID_HOSTCOM2_CONSOLE, + ID_HOSTCOM2_NONE, // 最後に置くこと + + ID_HOSTCOM_DBG_START, + ID_HOSTCOM_DBG_TCP, + ID_HOSTCOM_DBG_STDIO, + ID_HOSTCOM_DBG_CONSOLE, // 存在しないけど HOSTCOMn と揃える必要がある。 + ID_HOSTCOM_DBG_NONE, // 最後に置くこと。 + ID_SCALE_START, ID_SCALE_END = ID_SCALE_START + 6, @@ -89,6 +132,8 @@ enum { ID_FONTSIZE_24, ID_FONTSIZE_END, + ID_DEVICE_EMPTY, + ID_MONRATE_START, ID_MONRATE_END = ID_MONRATE_START + 4, @@ -170,6 +215,16 @@ wxBEGIN_EVENT_TABLE(WXMainFrame, inherit WXMainFrame::OnMenuInput) EVT_UPDATE_UI_RANGE(ID_INPUT_START + 1, ID_INPUT_END -1, WXMainFrame::OnMenuInputUI) + + EVT_MENU_RANGE(ID_HOSTNET0_START + 1, ID_HOSTNET1_NONE, + WXMainFrame::OnMenuHostNet) + EVT_UPDATE_UI_RANGE(ID_HOSTNET0_START + 1, ID_HOSTNET1_NONE, + WXMainFrame::OnMenuHostNetUI) + EVT_MENU_RANGE(ID_HOSTCOM0_START + 1, ID_HOSTCOM2_NONE, + WXMainFrame::OnMenuHostCom) + EVT_UPDATE_UI_RANGE(ID_HOSTCOM0_START + 1, ID_HOSTCOM2_NONE, + WXMainFrame::OnMenuHostComUI) + EVT_MENU_RANGE(ID_SCALE_START, ID_SCALE_END, WXMainFrame::OnMenuScale) EVT_UPDATE_UI_RANGE(ID_SCALE_START, ID_SCALE_END, @@ -214,6 +269,12 @@ wxBEGIN_EVENT_TABLE(WXMainFrame, inherit EVT_UPDATE_UI(ID_KEYBOARD_CONNECT, WXMainFrame::OnKeyboardConnectUI) EVT_MENU_RANGE(0, ID_SUBWIN_END, WXMainFrame::OnWindow) EVT_UPDATE_UI_RANGE(0, ID_SUBWIN_END, WXMainFrame::OnWindowUI) + + EVT_MENU_RANGE(ID_HOSTCOM_DBG_START + 1, ID_HOSTCOM_DBG_NONE, + WXMainFrame::OnMenuHostCom) + EVT_UPDATE_UI_RANGE(ID_HOSTCOM_DBG_START + 1, ID_HOSTCOM_DBG_NONE, + WXMainFrame::OnMenuHostComUI) + EVT_MENU(wxID_ABOUT, WXMainFrame::OnAbout) wxEND_EVENT_TABLE() @@ -222,11 +283,21 @@ WXMainFrame::WXMainFrame(wxWindow *paren wxDEFAULT_FRAME_STYLE & ~wxMAXIMIZE_BOX & ~wxRESIZE_BORDER) { // デバイスを取得 - mpu = GetMPUDevice(); power = GetPowerDevice(); syncer = GetSyncer(); // デバイスを取得。こっちはあるかどうかを調べる keyboard = gMainApp.FindObject(OBJ_KEYBOARD); + for (uint i = 0; i < hostnet.size(); i++) { + hostnet[i] = gMainApp.FindObject(OBJ_HOSTNET(i)); + } + for (uint i = 0; i < hostcom.size(); i++) { + hostcom[i] = gMainApp.FindObject(OBJ_HOSTCOM(i)); + } + hostcom_dbg = gMainApp.FindObject(OBJ_HOSTCOM_DBG); + + // メイン MPU 名を取得。メニューとタイトルによく出てくるので。 + // "88xx0" とか "88200" は別処理。 + mpuname = GetMPUDevice()->GetMPUName(); // メニュー wxMenuBar *menubar = new wxMenuBar(); @@ -250,7 +321,7 @@ WXMainFrame::WXMainFrame(wxWindow *paren menuVM->Append(ID_NMI_BUTTON, _("Push &Interrupt button")); } menuVM->AppendSeparator(); - menuVM->Append(ID_RESTART_VM, _("&Restart VM (For developers)"), ""); + menuVM->Append(ID_RESTART_VM, _("Re&start VM (For developers)"), ""); menuVM->AppendSeparator(); menuVM->Append(ID_EXIT, _("E&xit")); menubar->Append(menuVM, _("&VM")); @@ -264,6 +335,12 @@ WXMainFrame::WXMainFrame(wxWindow *paren menuSetInput->AppendRadioItem(ID_INPUT_JP, _("&JP Keyboard")); menuSet->AppendSubMenu(menuSetInput, _("&Key Input")); } + for (uint i = 0; i < hostnet.size(); i++) { + CreateHostNetMenu(menuSet, i); + } + for (uint i = 0; i < hostcom.size(); i++) { + CreateHostComMenu(menuSet, i); + } menubar->Append(menuSet, _("&Setting")); // メニュー > 表示 @@ -291,7 +368,7 @@ WXMainFrame::WXMainFrame(wxWindow *paren menuFontSize->AppendRadioItem(ID_FONTSIZE_24, "2&4"); menuDisplay->AppendSubMenu(menuFontSize, _("&Font Size")); wxMenu *menuMonRate = new wxMenu(); - user_idx = CreateMonRateTable(); + CreateMonRateTable(); for (int i = 0, end = monrates.size(); i < end; i++) { std::string text; switch (monrates[i]) { @@ -327,6 +404,13 @@ WXMainFrame::WXMainFrame(wxWindow *paren menuOper->AppendCheckItem(ID_KEYBOARD_CONNECT, _("Connect &Keyboard")); menuDevice->AppendSubMenu(menuOper, _("&Operation")); } + // アイテムが何もなければ本当はメニューバーのアイテムを無効にしたいが、 + // それは出来ないっぽい。何かアイテムを置かないと変なパネルが出たりする。 + if (menuDevice->GetMenuItems().IsEmpty()) { + // TRANSLATORS: This is "Device > Nothing" in the menubar. + menuDevice->Append(ID_DEVICE_EMPTY, _("Nothing")); + menuDevice->Enable(ID_DEVICE_EMPTY, false); + } menubar->Append(menuDevice, _("&Device")); #define AppendIfSeparator(menu, vmcap_) do { \ @@ -340,38 +424,48 @@ WXMainFrame::WXMainFrame(wxWindow *paren AppendIf(menuMonitor, ID_MONITOR_SCHEDULER, _("&Scheduler")); wxMenu *menuMPU = new wxMenu(); - AppendIf(menuMPU, ID_MONITOR_MPUREG, _("&Register")); + AppendIf(menuMPU, ID_MONITOR_MPUREG, _("&Registers")); AppendIf(menuMPU, ID_MONITOR_MPUATC, "&ATC"); - AppendIf(menuMPU, ID_MONITOR_MPUCACHE, _("Cache")); - AppendIf(menuMPU, ID_MONITOR_INTERRUPT, _("&Interrupt")); + AppendIf(menuMPU, ID_MONITOR_MPUCACHE, _("&Caches")); + AppendIf(menuMPU, ID_MONITOR_INTERRUPT, _("&Interrupts")); AppendIfSeparator(menuMPU, VMCap::M88K); - AppendIf(menuMPU, ID_MONITOR_CMMU7, "CMMU#7" + _("(Inst)")); + AppendIf(menuMPU, ID_MONITOR_CMMU7, + "CMMU#7" + _("(Inst)") + " " + _("Registers")); AppendIf(menuMPU, ID_MONITOR_ATC7, "ATC#7"); AppendIf(menuMPU, ID_SUBWIN_CACHE7, _("Cache") + "#7"); AppendIfSeparator(menuMPU, VMCap::M88K); - AppendIf(menuMPU, ID_MONITOR_CMMU6, "CMMU#6" + _("(Data)")); + AppendIf(menuMPU, ID_MONITOR_CMMU6, + "CMMU#6" + _("(Data)") + " " + _("Registers")); AppendIf(menuMPU, ID_MONITOR_ATC6, "ATC#6"); AppendIf(menuMPU, ID_SUBWIN_CACHE6, _("Cache") + "#6"); menuMPU->AppendSeparator(); // MEMDUMPn のラベルは UpdateUI で書き直すのでここでは適当に // 埋めておく。(empty だと怒られる) - for (int i = 0; i < MAX_MEMDUMP_MONITOR; i++) { + for (uint i = 0; i < MAX_MEMDUMP_MONITOR; i++) { AppendIf(menuMPU, ID_MONITOR_MEMDUMP(i), "memdump"); } menuMPU->AppendSeparator(); AppendIf(menuMPU, ID_SUBWIN_BRHIST, _("Branch &History")); AppendIf(menuMPU, ID_SUBWIN_EXHIST, _("&Exception History")); AppendIf(menuMPU, ID_SUBWIN_VECTOR, _("&Vector Table")); - menuMonitor->AppendSubMenu(menuMPU, - (gMainApp.Has(VMCap::M68K) ? "&MPU(MC68030)" : "&MPU(MC88xx0)")); + wxString mpulabel; + if (gMainApp.Has(VMCap::M68K)) { + mpulabel = "&MPU(" + mpuname + ")"; + } else if (gMainApp.Has(VMCap::M88K)) { + mpulabel = "&MPU(MC88xx0)"; + } else { + mpulabel = "&MPU"; + } + menuMonitor->AppendSubMenu(menuMPU, mpulabel); if (gMainApp.Has(VMCap::LUNA)) { wxMenu *menuXP = new wxMenu(); - AppendIf(menuXP, ID_MONITOR_XPREG, _("&Register")); - AppendIf(menuXP, ID_MONITOR_XPINTR, _("&Interrupt")); + AppendIf(menuXP, ID_MONITOR_XPREG, _("&Registers")); + AppendIf(menuXP, ID_MONITOR_XPINTR, _("&Interrupts")); AppendIf(menuXP, ID_MONITOR_XPIO, _("Internal &Devices")); + AppendIf(menuXP, ID_MONITOR_XPASCI, "&ASCI"); menuXP->AppendSeparator(); - for (int i = 0; i < MAX_XPMEMDUMP_MONITOR; i++) { + for (uint i = 0; i < MAX_XPMEMDUMP_MONITOR; i++) { AppendIf(menuXP, ID_MONITOR_XPMEMDUMP(i), "memdump"); } menuXP->AppendSeparator(); @@ -406,21 +500,23 @@ WXMainFrame::WXMainFrame(wxWindow *paren AppendIf(menuDev, ID_MONITOR_KEYBOARD, _("Keyboard/Mouse")); AppendIf(menuDev, ID_MONITOR_LANCE, "Lance"); AppendIf(menuDev, ID_MONITOR_NEREID, "Nereid"); - for (int i = 0; i < 2; i++) { - int id = ID_MONITOR_RTL8019AS(i); - wxString name = string_format("Nereid(RTL8019AS) #%d", i); + for (uint i = 0; i < hostnet.size(); i++) { + uint id = ID_MONITOR_RTL8019AS(i); + wxString name = string_format("Nereid#%u (RTL8019AS)", i); AppendIf(menuDev, id, name); } AppendIf(menuDev, ID_MONITOR_SYSPORT, _("System Port")); AppendIf(menuDev, ID_MONITOR_AREASET, _("Areaset")); AppendIf(menuDev, ID_MONITOR_LCD, "LCD"); AppendIf(menuDev, ID_MONITOR_SYSCLK, _("System Clock")); - for (int i = 0; i < 8; i++) { - int id = ID_MONITOR_VIRTIO_BLOCK(i); - wxString name = _("VirtIO Block") + string_format(" #%d", i); + for (uint i = 0; i < 8; i++) { + uint id = ID_MONITOR_VIRTIO_BLOCK(i); + wxString name = _("VirtIO Block") + string_format(" #%u", i); AppendIf(menuDev, id, name); } AppendIf(menuDev, ID_MONITOR_VIRTIO_NET, _("VirtIO Network")); + AppendIf(menuDev, ID_MONITOR_VIRTIO_SCSI, "VirtIO SCSI"); + AppendIf(menuDev, ID_MONITOR_VIRTIO_ENTROPY,_("VirtIO Entropy")); AppendIf(menuDev, ID_MONITOR_CRTC, "CRTC"); AppendIf(menuDev, ID_MONITOR_LUNAVC, _("Video Control")); AppendIf(menuDev, ID_MONITOR_BT45x, "Bt454/458"); @@ -429,41 +525,40 @@ WXMainFrame::WXMainFrame(wxWindow *paren AppendIf(menuDev, ID_MONITOR_RENDERER, _("Renderer")); AppendIf(menuDev, ID_SUBWIN_LUNAFB, _("Bitmap Plane")); AppendIf(menuDev, ID_SUBWIN_TVRAM, _("Text VRAM")); + AppendIf(menuDev, ID_MONITOR_SSG, "SSG"); AppendIf(menuDev, ID_MONITOR_ROMCONS, _("ROM Console (provisional)")); AppendIf(menuDev, ID_SUBWIN_ROM, "ROM"); // LUNA はバスが複数あるので Mainbus Device とする。 // 他の機種ではメインて言われても困るので Device とする。 if (gMainApp.Has(VMCap::LUNA)) { - menuMonitor->AppendSubMenu(menuDev, _("Mainbus De&vice")); + menuMonitor->AppendSubMenu(menuDev, _("Mainbus De&vices")); } else { - menuMonitor->AppendSubMenu(menuDev, _("De&vice")); + menuMonitor->AppendSubMenu(menuDev, _("De&vices")); } wxMenu *menuHost = new wxMenu(); AppendIf(menuHost, ID_MONITOR_WXHOSTINFO, _("Host &Information")); - if (gMainApp.IsX68030()) { - // X68030 ではネットワークは最大2つあるのでナンバリングが必要。 - // あれば表示ではなく、なければ Disable。 - for (int i = 0; i < 2; i++) { - int id = ID_MONITOR_HOSTNET(i); - wxString name = _("Host Network") + string_format(" #%d", i); - menuHost->AppendCheckItem(id, name); - if (gMonitorManager->Find(id) == NULL) { - menuHost->Enable(id, false); - } + for (uint i = 0; i < hostnet.size(); i++) { + uint id = ID_MONITOR_HOSTNET(i); + if (gMonitorManager->Find(id)) { + menuHost->AppendCheckItem(id, GetHostNetLabel(i)); + } + } + AppendIf(menuHost, ID_MONITOR_SLIRP, _("SLIRP Internal States")); + for (uint i = 0; i < hostcom.size(); i++) { + uint id = ID_MONITOR_HOSTCOM(i); + if (gMonitorManager->Find(id)) { + menuHost->AppendCheckItem(id, GetHostComLabel(i)); } - } else { - // それ以外ではネットワークは1つ固定なのでナンバリング不要 - AppendIf(menuHost, ID_MONITOR_HOSTNET(0), _("Host Network")); } - AppendIf(menuHost, ID_MONITOR_HOSTCOM, _("Host &Serial Port")); menuMonitor->AppendSubMenu(menuHost, _("&Host")); wxMenu *menuDebug = new wxMenu(); AppendIf(menuDebug, ID_SUBWIN_LOG, _("&Log")); - AppendIf(menuDebug, ID_MONITOR_BREAKPOINT, _("&Breakpoint")); + AppendIf(menuDebug, ID_MONITOR_BREAKPOINT, _("&Breakpoints")); menuDebug->AppendSeparator(); AppendIf(menuDebug, ID_SUBWIN_LOGSETTING, _("Log Level &Setting")); + CreateHostComMenu(menuDebug, -1); menuMonitor->AppendSubMenu(menuDebug, _("&Debug")); menubar->Append(menuMonitor, _("&Monitor")); @@ -483,14 +578,14 @@ WXMainFrame::WXMainFrame(wxWindow *paren SetMenuBar(menubar); - wxString title("nono"); + frame_title = wxString("nono"); const char *vmname = gMainApp.GetVMName(); if (vmname) { - title += '('; - title += wxString(vmname); - title += ')'; + frame_title += '('; + frame_title += wxString(vmname); + frame_title += ')'; } - SetTitle(title); + SetMyTitle(false); // UpdateUI イベントは Idle 時に時折チェックされるらしいが、 // (メインビューとサブウィンドウを合わせた) タイマーイベントの粒度が @@ -506,6 +601,16 @@ WXMainFrame::WXMainFrame(wxWindow *paren // mainview のほうを先に作成すること。 mainview = new WXMainView(this); statuspanel = new WXStatusPanel(this); + // 空き地用のパネル。 + spaceL = new WXBitmapPanel(this); + spaceR = new WXBitmapPanel(this); + spaceL->Hide(); + spaceR->Hide(); + + // Sizer 使わず自前でレイアウトする。 + SetAutoLayout(true); + // mainview のスケール、statuspanel のフォントサイズはいずれも + // コンストラクタの時点で初期状態がセットされている。 // SHOW イベントを最初にも一度起こしたいため // ステータスパネルを一旦非表示にする (これで SHOW(false) イベントが飛ぶ) @@ -516,8 +621,7 @@ WXMainFrame::WXMainFrame(wxWindow *paren statuspanel->Show(); } - // Sizer 使わず自前でレイアウトする。 - SetAutoLayout(true); + Fit(); // Activate イベントは、このトップレベルウィンドウにウィンドウフォーカスが // 来た or 外れたことを示すので、wxFrame (というかたぶん wxTopLevelWindow) @@ -536,6 +640,10 @@ WXMainFrame::WXMainFrame(wxWindow *paren wxCommandEventHandler(WXMainFrame::OnInsertFailed)); WXUIMessage::Connect(UIMessage::FDD_MEDIA_FAILED, this, wxCommandEventHandler(WXMainFrame::OnInsertFailed)); + WXUIMessage::Connect(UIMessage::HOSTNET_FAILED, this, + wxCommandEventHandler(WXMainFrame::OnHostNetFailed)); + WXUIMessage::Connect(UIMessage::HOSTCOM_FAILED, this, + wxCommandEventHandler(WXMainFrame::OnHostComFailed)); if (gMainApp.Has(VMCap::M68K)) { WXUIMessage::Connect(UIMessage::HALT, this, wxCommandEventHandler(WXMainFrame::OnHaltNotify)); @@ -550,6 +658,10 @@ WXMainFrame::~WXMainFrame() wxCommandEventHandler(WXMainFrame::OnInsertFailed)); WXUIMessage::Disconnect(UIMessage::FDD_MEDIA_FAILED, this, wxCommandEventHandler(WXMainFrame::OnInsertFailed)); + WXUIMessage::Disconnect(UIMessage::HOSTNET_FAILED, this, + wxCommandEventHandler(WXMainFrame::OnHostNetFailed)); + WXUIMessage::Disconnect(UIMessage::HOSTCOM_FAILED, this, + wxCommandEventHandler(WXMainFrame::OnHostComFailed)); if (gMainApp.Has(VMCap::M68K)) { WXUIMessage::Disconnect(UIMessage::HALT, this, wxCommandEventHandler(WXMainFrame::OnHaltNotify)); @@ -578,6 +690,83 @@ WXMainFrame::AppendIf(wxMenu *menu, int } } +// HostNet 用のメニューを作成して menuSet に追加する。 +void +WXMainFrame::CreateHostNetMenu(wxMenu *menuSet, uint unit) +{ + if (hostnet[unit] == NULL) { + return; + } + + int offset; + if (unit == 0) { + offset = ID_HOSTNET0_START - ID_HOSTNET0_START; + } else { + offset = ID_HOSTNET1_START - ID_HOSTNET0_START; + } + + wxMenu *menu = new wxMenu(); +#if defined(HAVE_HOSTNET_SLIRP) + menu->AppendRadioItem(offset + ID_HOSTNET0_USERMODE, "&usermode"); +#endif +#if defined(HAVE_HOSTNET_TAP) + menu->AppendRadioItem(offset + ID_HOSTNET0_TAP, "&tap"); +#endif +#if defined(HAVE_HOSTNET_BPF) + menu->AppendRadioItem(offset + ID_HOSTNET0_BPF, "&bpf"); +#endif +#if defined(HAVE_HOSTNET_AFPACKET) + menu->AppendRadioItem(offset + ID_HOSTNET0_AFPACKET, "&afpacket"); +#endif + menu->AppendRadioItem(offset + ID_HOSTNET0_NONE, "&none"); + menuSet->AppendSubMenu(menu, GetHostNetLabel(unit)); +} + +// HostCOM 用のメニューを作成して menuSet に追加する。 +// 引数の n は COM。ただし負数ならデバッガ用。 +void +WXMainFrame::CreateHostComMenu(wxMenu *menuSet, int n) +{ + HostCOMDevice *host; + + // デバッガ用は配列では最後。 + if (n < 0) { + host = hostcom_dbg; + } else { + host = hostcom[n]; + } + + if (host == NULL) { + return; + } + + int offset; + if (n == 0) { + offset = ID_HOSTCOM0_START - ID_HOSTCOM0_START; + } else if (n == 1) { + offset = ID_HOSTCOM1_START - ID_HOSTCOM0_START; + } else if (n == 2) { + offset = ID_HOSTCOM2_START - ID_HOSTCOM0_START; + } else { + offset = ID_HOSTCOM_DBG_START - ID_HOSTCOM0_START; + } + + wxMenu *menu = new wxMenu(); + menu->AppendRadioItem(offset + ID_HOSTCOM0_TCP, "&tcp"); + menu->AppendRadioItem(offset + ID_HOSTCOM0_STDIO, "&stdio"); + if (n >= 0 && gMainApp.FindObject(OBJ_CONSOLE)) { + menu->AppendRadioItem(offset + ID_HOSTCOM0_CONSOLE, "&console"); + } + menu->AppendRadioItem(offset + ID_HOSTCOM0_NONE, "&none"); + wxString name; + if (n >= 0) { + name = GetHostComLabel(n); + } else { + name = _("&Debugger"); + } + menuSet->AppendSubMenu(menu, name); +} + // リムーバブルデバイス用のメニューを作成して menuDevice に追加する void WXMainFrame::CreateRemovableMenu(wxMenu *menuDevice) @@ -597,10 +786,10 @@ WXMainFrame::CreateRemovableMenu(wxMenu } // CD, MO - auto spc = gMainApp.FindObject(OBJ_SPC); - if (spc) { + auto scsi = gMainApp.FindObject(OBJ_SCSI); + if (scsi) { for (int id = 0; id < 8; id++) { - scsidev[id] = spc->GetTarget(id); + scsidev[id] = scsi->GetTarget(id); if (scsidev[id]) { menu = CreateSCSIRemovableMenu(id); if (menu) { @@ -673,32 +862,45 @@ WXMainFrame::Init() return true; } -bool -WXMainFrame::Layout() +void +WXMainFrame::Fit() { - if (inherited::Layout() == false) { - return false; + wxSize statsize(0, 0); + if (statuspanel->IsShown()) { + statsize = statuspanel->GetMinSize(); } + const wxSize& viewsize = mainview->GetSize(); - wxSize msize = statuspanel->GetMinClientSize(); - wxSize ssize = statuspanel->GetClientSize(); - wxSize vsize = mainview->GetClientSize(); + wxSize size(std::max(statsize.x, viewsize.x), statsize.y + viewsize.y); + SetClientSize(size); +} + +bool +WXMainFrame::Layout() +{ + const wxSize& client = GetClientSize(); + wxSize statsize(0, 0); if (statuspanel->IsShown()) { - ssize.y = msize.y; - } else { - ssize.y = 0; + statsize = statuspanel->GetSize(); + statuspanel->SetSize(0, 0, client.x, statsize.y); } - wxSize size; - size.x = std::max(msize.x, vsize.x); - size.y = ssize.y + vsize.y; - - if (ssize.y != 0) { - statuspanel->SetSize(0, 0, size.x, ssize.y); + // メインビューの方が小さければ両側に空き地を入れてセンタリングする。 + wxSize viewsize = mainview->GetSize(); + if (viewsize.x < client.x) { + int view_x = (client.x - viewsize.x) / 2; + spaceL->SetSize(0, statsize.y, view_x, viewsize.y); + spaceL->Show(); + mainview->SetSize(view_x, statsize.y, viewsize.x, viewsize.y); + int x = view_x + viewsize.x; + spaceR->SetSize(x, statsize.y, client.x - x, viewsize.y); + spaceR->Show(); + } else { + mainview->SetPosition(wxPoint(0, statsize.y)); + spaceL->Hide(); + spaceR->Hide(); } - mainview->SetSize(0, ssize.y, size.x, vsize.y); - SetClientSize(size); return true; } @@ -873,6 +1075,197 @@ WXMainFrame::OnMenuInputUI(wxUpdateUIEve } } +// メニューの「設定 > HostNet* > *」の選択肢イベント +void +WXMainFrame::OnMenuHostNet(wxCommandEvent& event) +{ + int id = event.GetId(); + uint unit; + uint choice; + + if (id <= ID_HOSTNET0_NONE) { + unit = 0; + choice = id; + } else { + unit = 1; + choice = id - ID_HOSTNET1_START + ID_HOSTNET0_START; + } + + // SLIRP モニタウィンドウはあれば閉じておく必要がある。 + if ((bool)windows[ID_MONITOR_SLIRP]) { + DoWindow(ID_MONITOR_SLIRP, false); + } + + // 設定を更新。 + std::string line = hostnet[unit]->GetConfigKey() + "-driver="; + switch (choice) { + case ID_HOSTNET0_USERMODE: line += "usermode"; break; + case ID_HOSTNET0_TAP: line += "tap"; break; + case ID_HOSTNET0_BPF: line += "bpf"; break; + case ID_HOSTNET0_AFPACKET: line += "afpacket"; break; + case ID_HOSTNET0_NONE: line += "none"; break; + default: + assert(false); + } + gConfig->UpdateRunning(line); + + // ホストスレッドに通知。 + hostnet[unit]->NotifyReselectDriver(); +} + +// メニューの「設定 > HostNet* > *」の UI +void +WXMainFrame::OnMenuHostNetUI(wxUpdateUIEvent& event) +{ + int id = event.GetId(); + uint unit; + + if (id <= ID_HOSTNET0_NONE) { + unit = 0; + } else { + unit = 1; + id = id - ID_HOSTNET1_START + ID_HOSTNET0_START; + } + + const std::string driver = hostnet[unit]->GetDriverName(); + uint selected; + if (driver == "usermode") { + selected = ID_HOSTNET0_USERMODE; + } else if (driver == "tap") { + selected = ID_HOSTNET0_TAP; + } else if (driver == "bpf") { + selected = ID_HOSTNET0_BPF; + } else if (driver == "afpacket") { + selected = ID_HOSTNET0_AFPACKET; + } else { + selected = ID_HOSTNET0_NONE; + } + + event.Check((id == selected)); +} + +// メニューの「設定 > HostCom* > *」の選択肢イベント +void +WXMainFrame::OnMenuHostCom(wxCommandEvent& event) +{ + int id = event.GetId(); + HostCOMDevice *host; + uint choice; + + if (id <= ID_HOSTCOM0_NONE) { + host = hostcom[0]; + choice = id; + } else if (id <= ID_HOSTCOM1_NONE) { + host = hostcom[1]; + choice = id - ID_HOSTCOM1_START + ID_HOSTCOM0_START; + } else if (id <= ID_HOSTCOM2_NONE) { + host = hostcom[2]; + choice = id - ID_HOSTCOM2_START + ID_HOSTCOM0_START; + } else { + host = hostcom_dbg; + choice = id - ID_HOSTCOM_DBG_START + ID_HOSTCOM0_START; + } + + // 設定を更新。 + std::string line = host->GetConfigKey() + "-driver="; + switch (choice) { + case ID_HOSTCOM0_TCP: line += "tcp"; break; + case ID_HOSTCOM0_STDIO: line += "stdio"; break; + case ID_HOSTCOM0_CONSOLE: line += "console"; break; + case ID_HOSTCOM0_NONE: line += "none"; break; + default: + assert(false); + } + gConfig->UpdateRunning(line); + + // ホストスレッドに通知。 + host->NotifyReselectDriver(); +} + +// メニューの「設定 > HostCom* > *」の UI +void +WXMainFrame::OnMenuHostComUI(wxUpdateUIEvent& event) +{ + int id = event.GetId(); + HostCOMDevice *host; + + if (id <= ID_HOSTCOM0_NONE) { + host = hostcom[0]; + } else if (id <= ID_HOSTCOM1_NONE) { + host = hostcom[1]; + id = id - ID_HOSTCOM1_START + ID_HOSTCOM0_START; + } else if (id <= ID_HOSTCOM2_NONE) { + host = hostcom[2]; + id = id - ID_HOSTCOM2_START + ID_HOSTCOM0_START; + } else { + host = hostcom_dbg; + id = id - ID_HOSTCOM_DBG_START + ID_HOSTCOM0_START; + } + + const std::string driver = host->GetDriverName(); + uint selected; + if (driver == "tcp") { + selected = ID_HOSTCOM0_TCP; + } else if (driver == "stdio") { + selected = ID_HOSTCOM0_STDIO; + } else if (driver == "console") { + selected = ID_HOSTCOM0_CONSOLE; + } else { + selected = ID_HOSTCOM0_NONE; + } + + event.Check((id == selected)); +} + +// hostnet ドライバ起動失敗のメッセージ。 +void +WXMainFrame::OnHostNetFailed(wxCommandEvent& event) +{ + wxString hostdev; + wxString errmsg; + uint n = event.GetInt(); + + hostdev.Printf("hostnet%u", n); + errmsg = hostnet[n]->GetErrmsg(); + HostDriverFailed(hostdev, errmsg); +} + +void +WXMainFrame::OnHostComFailed(wxCommandEvent& event) +{ + wxString hostdev; + wxString errmsg; + int n = event.GetInt(); + + if (n >= 0) { + hostdev.Printf("hostcom%u", n); + errmsg = hostcom[n]->GetErrmsg(); + } else { + hostdev = "debugger"; + errmsg = hostcom_dbg->GetErrmsg(); + } + HostDriverFailed(hostdev, errmsg); +} + +// ホストドライバ起動失敗のメッセージ。 +void +WXMainFrame::HostDriverFailed(const wxString& hostdev, const wxString& errmsg) +{ + wxString msg; + + msg = hostdev; + msg += ": "; + msg += _("Failed to switch the driver.\n" + "(Using 'none' instead)"); + if (!errmsg.empty()) { + msg += "\n\n"; + msg += _("Error message:"); + msg += ' '; + msg += errmsg; + } + ::wxMessageBox(msg); +} + // スケール一覧 /*static*/ std::vector WXMainFrame::view_scales { @@ -919,7 +1312,7 @@ WXMainFrame::OnMenuScale(wxCommandEvent& int idx = event.GetId() - ID_SCALE_START; mainview->DoResize(view_scales[idx]); // 再レイアウト - Layout(); + Fit(); } // メニューの「表示 > スケール > *」の共通 UI @@ -971,7 +1364,7 @@ WXMainFrame::OnMenuFontSize(wxCommandEve statuspanel->FontChanged(); // ステータスパネルの大きさが変わるので再レイアウト - Layout(); + Fit(); } } @@ -993,10 +1386,8 @@ WXMainFrame::monrates { 1, }; -// 「表示 > モニタ更新頻度」のメニュー項目作成に必要な monrates を作成し、 -// ユーザ指定値があれば monrates[] 内のインデックスを返す。 -// ユーザ指定値がなければ -1 を返す。 -int +// 「表示 > モニタ更新頻度」のメニュー項目作成に必要な monrates を作成する。 +void WXMainFrame::CreateMonRateTable() { // 設定ファイル monitor-rate で指定された値を追加。 @@ -1010,16 +1401,7 @@ WXMainFrame::CreateMonRateTable() std::sort(monrates.begin(), monrates.end(), [](int a, int b) { return a > b; } ); - - // ユーザ指定の値が何番目かを返す。指定されてなければ -1。 - for (int i = 0, end = monrates.size(); i < end; i++) { - if (monrates[i] == user_rate) { - return i; - } - } - // 見付からないことはないはずだが } - return -1; } // メニューの「表示 > モニタ更新頻度 > *」の共通イベント @@ -1062,7 +1444,7 @@ WXMainFrame::OnShowStatusPanel(wxCommand statuspanel->Show(enable); // 再レイアウト - Layout(); + Fit(); } // メニューの「表示 > ステータスパネルを表示」UI @@ -1261,12 +1643,6 @@ WXMainFrame::OnMouseMode(wxCommandEvent& // enable ならチェックを付けようとして呼ばれた bool enable = event.IsChecked(); - if (enable) { - // メッセージを表示したい - } else { - // メッセージを表示したい - } - // マウスモードを設定 wxCommandEvent newev(NONO_EVT_MOUSEMODE, GetId()); newev.SetEventObject(this); @@ -1310,6 +1686,13 @@ WXMainFrame::OnWindow(wxCommandEvent& ev DoWindow(id, event.IsChecked()); } +#define SetMonitor(id, name) do { \ + try { \ + windows[id].reset(new WXMonitorWindow(this, (name), \ + gMonitorManager->Get(id))); \ + } catch (...) { } \ +} while (0) + void WXMainFrame::DoWindow(int id, bool enable) { @@ -1317,15 +1700,16 @@ WXMainFrame::DoWindow(int id, bool enabl // id はモニター ID であると同時に、windows[] 配列の添字、さらにこの // モニタウィンドウの wxWindowID としても使っている // (WXSubWindow::OnClose() 参照)。 -#define SetMonitor(id, name) \ - windows[id].reset(new WXMonitorWindow(this, (name), \ - gMonitorManager->Get(id))) if (enable) { // チェックが入ったのでウィンドウを作成 switch (id) { case ID_MONITOR_ACCSTAT: - SetMonitor(id, _("Access Status")); + // こいつだけモニタ ID を持ちつつ上位互換のサブウィンドウがある。 + try { + windows[id].reset(new + WXAccStatWindow(this, gMonitorManager->Get(id))); + } catch (...) { } break; case ID_MONITOR_AREASET: @@ -1341,8 +1725,8 @@ WXMainFrame::DoWindow(int id, bool enabl case ID_MONITOR_ATC6: case ID_MONITOR_ATC7: { - int n = id - ID_MONITOR_ATC0; - wxString name(string_format("ATC#%d", n)); + uint n = id - ID_MONITOR_ATC0; + wxString name(string_format("ATC#%u", n)); if ((n & 1) == 0) { name += _("(Data)"); } else { @@ -1353,7 +1737,7 @@ WXMainFrame::DoWindow(int id, bool enabl } case ID_MONITOR_BREAKPOINT: - SetMonitor(id, _("Breakpoint")); + SetMonitor(id, _("Breakpoints")); break; case ID_MONITOR_BT45x: @@ -1369,13 +1753,15 @@ WXMainFrame::DoWindow(int id, bool enabl case ID_MONITOR_CMMU6: case ID_MONITOR_CMMU7: { - int n = id - ID_MONITOR_CMMU0; - wxString name(string_format("CMMU#%d", n)); + uint n = id - ID_MONITOR_CMMU0; + wxString name(string_format("CMMU#%u", n)); if ((n & 1) == 0) { name += _("(Data)"); } else { name += _("(Inst)"); } + name += ' '; + name += _("Registers"); SetMonitor(id, name); break; } @@ -1392,30 +1778,31 @@ WXMainFrame::DoWindow(int id, bool enabl SetMonitor(id, "FDC (uPD72065B)"); break; - case ID_MONITOR_HOSTCOM: - SetMonitor(id, _("Host Serial Port")); + case ID_MONITOR_HOSTCOM0: + case ID_MONITOR_HOSTCOM1: + case ID_MONITOR_HOSTCOM2: + { + uint n = id - ID_MONITOR_HOSTCOM0; + SetMonitor(id, GetHostComLabel(n)); break; + } case ID_MONITOR_HOSTNET0: case ID_MONITOR_HOSTNET1: { - wxString name = _("Host Network"); - if (gMainApp.IsX68030()) { - int n = id - ID_MONITOR_HOSTNET0; - name += string_format(" #%d", n); - } - SetMonitor(id, name); + uint n = id - ID_MONITOR_HOSTNET0; + SetMonitor(id, GetHostNetLabel(n)); break; } case ID_MONITOR_INTERRUPT: { wxString name; - if (gMainApp.Has(VMCap::M88K)) { - // 実際はほぼシステムコントローラなのでややこしい。 - name = "MPU " + _("Interrupt"); + if (gMainApp.Has(VMCap::M68K)) { + name = MPUName() + " " + _("Interrupts"); } else { - name = MPUName() + " " + _("Interrupt"); + // 実際はほぼシステムコントローラなのでややこしい。 + name = "MPU " + _("Interrupts"); } SetMonitor(id, name); break; @@ -1430,7 +1817,9 @@ WXMainFrame::DoWindow(int id, bool enabl break; case ID_MONITOR_LCD: - windows[id].reset(new WXLCDMonitor(this)); + try { + windows[id].reset(new WXLCDMonitor(this)); + } catch (...) { } break; case ID_MONITOR_LUNAVC: @@ -1454,7 +1843,9 @@ WXMainFrame::DoWindow(int id, bool enabl case ID_MONITOR_XPMEMDUMP0 ... ID_MONITOR_XPMEMDUMP(MAX_XPMEMDUMP_MONITOR - 1): { - windows[id].reset(new WXMemdumpWindow(this, id)); + try { + windows[id].reset(new WXMemdumpWindow(this, id)); + } catch (...) { } break; } @@ -1471,11 +1862,11 @@ WXMainFrame::DoWindow(int id, bool enabl break; case ID_MONITOR_MPUCACHE: - SetMonitor(id, MPUName() + " " + _("Cache")); + SetMonitor(id, MPUName() + " " + _("Caches")); break; case ID_MONITOR_MPUREG: - SetMonitor(id, MPUName() + " " + _("Register")); + SetMonitor(id, MPUName() + " " + _("Registers")); break; case ID_MONITOR_NEREID: @@ -1513,8 +1904,8 @@ WXMainFrame::DoWindow(int id, bool enabl case ID_MONITOR_RTL8019AS0: case ID_MONITOR_RTL8019AS1: { - int n = id - ID_MONITOR_RTL8019AS0; - wxString name = string_format("Nereid (RTL8019AS) #%d", n); + uint n = id - ID_MONITOR_RTL8019AS0; + wxString name = string_format("Nereid#%u (RTL8019AS)", n); SetMonitor(id, name); break; } @@ -1535,10 +1926,18 @@ WXMainFrame::DoWindow(int id, bool enabl SetMonitor(id, "SIO (uPD7201)"); break; + case ID_MONITOR_SLIRP: + SetMonitor(id, _("SLIRP Internal States")); + break; + case ID_MONITOR_SPC: SetMonitor(id, "SPC (MB89352)"); break; + case ID_MONITOR_SSG: + SetMonitor(id, "SSG (YM2149)"); + break; + case ID_MONITOR_SYSCLK: SetMonitor(id, _("System Clock")); break; @@ -1550,8 +1949,8 @@ WXMainFrame::DoWindow(int id, bool enabl case ID_MONITOR_VIRTIO_BLOCK0 ... ID_MONITOR_VIRTIO_BLOCK7: { - int n = id - ID_MONITOR_VIRTIO_BLOCK0; - wxString name = _("VirtIO Block") + string_format(" #%d", n); + uint n = id - ID_MONITOR_VIRTIO_BLOCK0; + wxString name = _("VirtIO Block") + string_format(" #%u", n); SetMonitor(id, name); break; } @@ -1560,16 +1959,28 @@ WXMainFrame::DoWindow(int id, bool enabl SetMonitor(id, _("VirtIO Network")); break; + case ID_MONITOR_VIRTIO_SCSI: + SetMonitor(id, "VirtIO SCSI"); + break; + + case ID_MONITOR_VIRTIO_ENTROPY: + SetMonitor(id, _("VirtIO Entropy")); + break; + case ID_MONITOR_WXHOSTINFO: SetMonitor(id, _("Host Information")); break; + case ID_MONITOR_XPASCI: + SetMonitor(id, "HD647180 ASCI"); + break; + case ID_MONITOR_XPREG: - SetMonitor(id, "HD647180 " + _("Register")); + SetMonitor(id, "HD647180 " + _("Registers")); break; case ID_MONITOR_XPINTR: - SetMonitor(id, "HD647180 " + _("Interrupt")); + SetMonitor(id, "HD647180 " + _("Interrupts")); break; case ID_MONITOR_XPIO: @@ -1579,16 +1990,20 @@ WXMainFrame::DoWindow(int id, bool enabl case ID_SUBWIN_BRHIST: { wxString name = MPUName() + " " + _("Branch History"); - windows[id].reset(new WXScrollMonitorWindow(this, name, - gMonitorManager->Get(id))); + try { + windows[id].reset(new WXScrollMonitorWindow(this, name, + gMonitorManager->Get(id))); + } catch (...) { } break; } case ID_SUBWIN_EXHIST: { wxString name = MPUName() + " " + _("Exception History"); - windows[id].reset(new WXScrollMonitorWindow(this, name, - gMonitorManager->Get(id))); + try { + windows[id].reset(new WXScrollMonitorWindow(this, name, + gMonitorManager->Get(id))); + } catch (...) { } break; } @@ -1601,31 +2016,43 @@ WXMainFrame::DoWindow(int id, bool enabl case ID_SUBWIN_CACHE6: case ID_SUBWIN_CACHE7: { - int n = id - ID_SUBWIN_CACHE0; + uint n = id - ID_SUBWIN_CACHE0; wxString name = _("Cache"); - name += string_format("#%d", n); + name += string_format("#%u", n); if ((n & 1) == 0) { name += _("(Data)"); } else { name += _("(Inst)"); } - windows[id].reset(new WXCacheWindow(this, name, - gMonitorManager->Get(id))); + try { + windows[id].reset(new WXCacheWindow(this, name, + gMonitorManager->Get(id))); + } catch (...) { } break; } case ID_SUBWIN_DIPSW: - windows[id].reset(new WXDipswWindow(this)); + try { + windows[id].reset(new WXDipswWindow(this)); + } catch (...) { } break; case ID_SUBWIN_LCDPANEL: - windows[id].reset(new WXLCDWindow(this)); + try { + windows[id].reset(new WXLCDWindow(this)); + } catch (...) { } break; + case ID_SUBWIN_LOG: - windows[id].reset(new WXLogMonitor(this)); + try { + windows[id].reset(new WXLogMonitor(this)); + } catch (...) { } break; + case ID_SUBWIN_LOGSETTING: - windows[id].reset(new WXLogSettingWindow(this)); + try { + windows[id].reset(new WXLogSettingWindow(this)); + } catch (...) { } break; case ID_SUBWIN_LUNAFB: @@ -1638,17 +2065,19 @@ WXMainFrame::DoWindow(int id, bool enabl } else { name = _("Text VRAM"); } - windows[id].reset(new WXPlaneVRAMWindow(this, name)); + try { + windows[id].reset(new WXPlaneVRAMWindow(this, name)); + } catch (...) { } break; } case ID_SUBWIN_NEWSIO: - { - windows[id].reset(new WXScrollMonitorWindow(this, - _("Device Map (NEWS)"), - gMonitorManager->Get(id))); + try { + windows[id].reset(new WXScrollMonitorWindow(this, + _("Device Map (NEWS)"), + gMonitorManager->Get(id))); + } catch (...) { } break; - } case ID_SUBWIN_PALETTE: case ID_SUBWIN_TEXTPAL: @@ -1660,47 +2089,60 @@ WXMainFrame::DoWindow(int id, bool enabl } else { name = _("Palette Colormap"); } - windows[id].reset(new WXPaletteWindow(this, name)); + try { + windows[id].reset(new WXPaletteWindow(this, name)); + } catch (...) { } break; } case ID_SUBWIN_ROM: - windows[id].reset(new WXROMWindow(this)); + try { + windows[id].reset(new WXROMWindow(this)); + } catch (...) { } break; case ID_SUBWIN_SOFTKEY: - windows[id].reset(new WXSoftKeyWindow(this, gMainApp.GetVMType())); + try { + windows[id].reset(new WXSoftKeyWindow(this, + gMainApp.GetVMType())); + } catch (...) { } break; case ID_SUBWIN_VECTOR: { wxString name = MPUName() + " " + _("Vector Table"); - windows[id].reset(new WXScrollMonitorWindow(this, name, - gMonitorManager->Get(id))); + try { + windows[id].reset(new WXScrollMonitorWindow(this, name, + gMonitorManager->Get(id))); + } catch (...) { } break; } case ID_SUBWIN_X68KIO: - { - windows[id].reset(new WXScrollMonitorWindow(this, - _("Device Map (24bit space)"), - gMonitorManager->Get(id))); + try { + windows[id].reset(new WXScrollMonitorWindow(this, + _("Device Map (24bit space)"), + gMonitorManager->Get(id))); + } catch (...) { } break; - } case ID_SUBWIN_XPBRHIST: { wxString name = "HD647180 " + _("Branch History"); - windows[id].reset(new WXScrollMonitorWindow(this, name, - gMonitorManager->Get(id))); + try { + windows[id].reset(new WXScrollMonitorWindow(this, name, + gMonitorManager->Get(id))); + } catch (...) { } break; } case ID_SUBWIN_XPEXHIST: { wxString name = "HD647180 " + _("Exception History"); - windows[id].reset(new WXScrollMonitorWindow(this, name, - gMonitorManager->Get(id))); + try { + windows[id].reset(new WXScrollMonitorWindow(this, name, + gMonitorManager->Get(id))); + } catch (...) { } break; } @@ -1724,22 +2166,29 @@ WXMainFrame::OnWindowUI(wxUpdateUIEvent& // ウィンドウが存在していればチェックを表示 event.Check((bool)windows[id]); + // SLIRP モニタだけ無効状態がある。 +#if defined(HAVE_HOSTNET_SLIRP) + if (__predict_false(id == ID_MONITOR_SLIRP)) { + event.Enable(NetDriverSlirp::IsOccupied()); + } +#endif + if (IS_MONITOR_MEMDUMP(id) || IS_MONITOR_XPMEMDUMP(id)) { // メニューに現在のアドレスを載せる // (ウィンドウの生存期間外にも呼ばれることに注意) auto mon = gMonitorManager->Get(id); - auto *memdump = dynamic_cast(mon.obj); + auto *memdump = dynamic_cast(mon->obj); assert(memdump); - uint32 addr = memdump->GetAddr(); + uint32 addr = memdump->GetAddr().Addr(); - int n; + uint n; wxString text = _("Memory Dump"); if (IS_MONITOR_XPMEMDUMP(id)) { n = id - ID_MONITOR_XPMEMDUMP0; - text += string_format(" &%d: $%05x", n, addr); + text += string_format(" &%u: $%05x", n, addr); } else { n = id - ID_MONITOR_MEMDUMP0; - text += string_format(" &%d: $%08x", n, addr); + text += string_format(" &%u: $%08x", n, addr); } event.SetText(text); } @@ -1826,14 +2275,6 @@ WXMainFrame::DeleteWindow(wxWindow *win) } } -// メイン MPU 名を返す。メニューとタイトルによく出てくるので。 -// 88xx0 とか 88200 は別処理。 -wxString -WXMainFrame::MPUName() const -{ - return mpu->GetMPUName(); -} - // m680x0 ダブルバスフォールト処理 void WXMainFrame::OnHaltNotify(wxCommandEvent& event) @@ -1843,6 +2284,36 @@ WXMainFrame::OnHaltNotify(wxCommandEvent wxICON_EXCLAMATION); } +// HostNet に対する表示用テキストを返す。 +wxString +WXMainFrame::GetHostNetLabel(uint n) const +{ + return wxString(string_format("HostNet%u: ", n) + + hostnet[n]->GetPortName()); +} + +// HostCOM に対する表示用テキストを返す。 +// デバッガ用は呼び出し側で処理すること。 +wxString +WXMainFrame::GetHostComLabel(uint n) const +{ + assert((int)n >= 0); + return wxString(string_format("HostCom%u: ", n) + + hostcom[n]->GetPortName()); +} + +// メインウィンドウのタイトルを (mousemode によって) 変更する。 +void +WXMainFrame::SetMyTitle(bool mousemode) +{ + wxString new_title = frame_title; + if (mousemode) { + // メッセージを表示したい + new_title += " (CTRL + F12 to quit mouse mode)"; + } + SetTitle(new_title); +} + // 起動時にオープンするサブウィンドウ (-M オプション) /*static*/ std::array WXMainFrame::subwindow_start;