--- nono/wx/wxstatuspanel.cpp 2026/04/29 17:05:12 1.1.1.5 +++ nono/wx/wxstatuspanel.cpp 2026/04/29 17:05:16 1.1.1.6 @@ -24,14 +24,12 @@ #include "wxmainview.h" #include "wxuimessage.h" #include "wxversion.h" -#include "ethernet.h" #include "fdc.h" #include "hostnet.h" +#include "newsctlr.h" #include "power.h" #include "spc.h" -#include "sync.h" - -WXStatusPanel *gStatusPanel; +#include "syncer.h" wxBEGIN_EVENT_TABLE(WXStatusPanel, inherited) EVT_CLOSE(WXStatusPanel::OnClose) @@ -51,7 +49,8 @@ static const long STATUS_PANEL_STYLE = 0 // コンストラクタ WXStatusPanel::WXStatusPanel(wxWindow *parent) - : inherited(parent, wxDefaultSize, STATUS_PANEL_STYLE) + : inherited(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, + STATUS_PANEL_STYLE) { timer.SetOwner(this); @@ -66,10 +65,12 @@ WXStatusPanel::WXStatusPanel(wxWindow *p // 分かりづらくて、こっちがフォーカス持ってしまうと (というか起動後は // こっちにある) VM にキー入力が出来ずに焦ることになるので、ここへの // キー入力イベントは全部メインビューに飛ばす。 + auto mainframe = dynamic_cast(GetParent()); + auto mainview = mainframe->GetMainView(); Connect(wxEVT_KEY_UP, wxKeyEventHandler(WXMainView::OnKeyUp), NULL, - gMainView); + mainview); Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(WXMainView::OnKeyDown), NULL, - gMainView); + mainview); // VM からの通知を受け取る WXUIMessage::Connect(UIMessage::SCSI_MEDIA_CHANGE, this, @@ -89,11 +90,11 @@ WXStatusPanel::~WXStatusPanel() delete ind; } - WXUIMessage::Disconnect(UIMessage::SCSI_MEDIA_CHANGE, + WXUIMessage::Disconnect(UIMessage::SCSI_MEDIA_CHANGE, this, wxCommandEventHandler(WXStatusPanel::OnSCSIMediaChanged)); - WXUIMessage::Disconnect(UIMessage::FDD_MEDIA_CHANGE, + WXUIMessage::Disconnect(UIMessage::FDD_MEDIA_CHANGE, this, wxCommandEventHandler(WXStatusPanel::OnFDDMediaChanged)); - WXUIMessage::Disconnect(UIMessage::LED, + WXUIMessage::Disconnect(UIMessage::LED, this, wxCommandEventHandler(WXStatusPanel::OnLEDChanged)); } @@ -134,6 +135,23 @@ WXStatusPanel::FontChanged() { inherited::FontChanged(); + // アクセスマークをサイズに応じて作り直す + const uint8 *src; + switch (font_height) { + case 12: + src = AccessMark12; + break; + case 16: + src = AccessMark16; + break; + case 24: + src = AccessMark24; + break; + default: + PANIC("Unexpected font_height=%d", font_height); + } + accmark.reset(new BitmapI8(src, font_height, font_height)); + // インジケータを再レイアウト LayoutIndicators(); @@ -181,83 +199,99 @@ static const std::vector data = { void WXStatusPanel::InitIndicators() { + Indicator *ind; + // パフォーマンスカウンタ - Indicator *perf = new Indicator(Indicator::PERF, 8/* >>>9999% */, + syncer = GetSyncer(); + ind = new Indicator(Indicator::PERF, 8/* >>>9999% */, &WXStatusPanel::DrawPerf); - perf->dclick = &WXStatusPanel::DClickPerf; - indicators.emplace_back(perf); + ind->dclick = &WXStatusPanel::DClickPerf; + indicators.emplace_back(ind); // SCSI // SPC の接続済みデバイスリストから取得。 // (ホストアダプタ2つ目のことは考えてない) - const std::vector& conn = gSPC->GetConnectedDevices(); - for (const auto& dev : conn) { - SCSI::DevType devtype = dev->GetDevType(); - if (devtype == SCSI::DevType::Initiator) { - continue; - } - int scsiid = dev->GetMyID(); - - // 文字列は OnSCSIMediaChanged() でセットする。 - Indicator *si = new Indicator(Indicator::SCSI0 + scsiid, 3, - &WXStatusPanel::DrawSCSI); - si->contextmenu = &WXStatusPanel::ContextMenuCD; - si->dev = dev; - si->panel = new wxPanel(this); - // このパネルがフォーカスを受け取らないようにする。 - // StatusPanel がフォーカスを持っていてもキー入力を MainFrame に渡す - // ようにしているため、StatusPanel のフォーカスを奪ってはいけない。 - si->panel->SetCanFocus(false); + auto spc = gMainApp.FindObject(OBJ_SPC); + if (spc) { + const std::vector& conn = spc->GetConnectedDevices(); + for (const auto& dev : conn) { + SCSI::DevType devtype = dev->GetDevType(); + if (devtype == SCSI::DevType::Initiator) { + continue; + } + int scsiid = dev->GetMyID(); + + // 文字列は OnSCSIMediaChanged() でセットする。 + ind = new Indicator(Indicator::SCSI0 + scsiid, 3, + &WXStatusPanel::DrawSCSI); + ind->contextmenu = &WXStatusPanel::ContextMenuCD; + ind->dev = dev; + ind->panel = new wxPanel(this); + // このパネルがフォーカスを受け取らないようにする。 + // StatusPanel がフォーカスを持っていてもキー入力を MainFrame に渡す + // ようにしているため、StatusPanel のフォーカスを奪ってはいけない。 + ind->panel->SetCanFocus(false); - indicators.emplace_back(si); + indicators.emplace_back(ind); + } + // BSY 取得用 + scsibus = spc->GetSCSIBus(); } - // BSY 取得用 - scsibus = gSPC->GetSCSIBus(); // ネットワーク - if (gEthernet) { - hostnet = gEthernet->GetHostNet(); - assert(hostnet); + hostnet = gMainApp.FindObject(OBJ_HOSTNET); + if (hostnet) { if (hostnet->GetDriverName() == "none") { net_ok = DISABLE; } else { net_ok = ENABLE; } // \x1e は上向き矢印、\x1f は下向き矢印 - Indicator *net = new Indicator(Indicator::LAN, 5, - &WXStatusPanel::DrawNet); - net->text = "LAN\x1e\x1f"; - indicators.emplace_back(net); + ind = new Indicator(Indicator::LAN, 5, + &WXStatusPanel::DrawNet, "LAN\x1e\x1f"); + indicators.emplace_back(ind); } else { net_ok = NOT_AVAILABLE; } // FD - if (gFDC) { - const std::vector& fdd_vector = gFDC->GetFDD(); - for (const auto fdd : fdd_vector) { - if (fdd) { - int unit = fdd->GetUnitNo(); - // 文字列は OnFDDMediaChanged() でセットする。 - Indicator *ind = new Indicator(Indicator::FDD0 + unit, 7, - &WXStatusPanel::DrawFD); - - ind->contextmenu = &WXStatusPanel::ContextMenuFD; - ind->dev = fdd; - ind->panel = new wxPanel(this); - // フォーカスを受け取らない。少し上の CD のところ参照。 - ind->panel->SetCanFocus(false); - - indicators.emplace_back(ind); - } + for (int unit = 0; unit < FDCDevice::MAX_DRIVE; unit++) { + auto fdd = gMainApp.FindObject(OBJ_FDD(unit)); + if (fdd) { + // 存在するドライブのリスト + fdd_vector.push_back(fdd); + + // 文字列は OnFDDMediaChanged() でセットする。 + ind = new Indicator(Indicator::FDD0 + unit, 7, + &WXStatusPanel::DrawFD); + + ind->contextmenu = &WXStatusPanel::ContextMenuFD; + ind->dev = fdd; + ind->panel = new wxPanel(this); + // フォーカスを受け取らない。少し上の CD のところ参照。 + ind->panel->SetCanFocus(false); + + indicators.emplace_back(ind); } } + // NEWS の LED (2->1 の順で並べる) + newsctlr = gMainApp.FindObject(OBJ_NEWSCTLR); + if (newsctlr) { + ind = new Indicator(Indicator::NEWSLED2, 2, + &WXStatusPanel::DrawNewsLED2, "LED2"); + indicators.emplace_back(ind); + + ind = new Indicator(Indicator::NEWSLED1, 2, + &WXStatusPanel::DrawNewsLED1, "LED1"); + indicators.emplace_back(ind); + } + // 電源 LED - Indicator *power = new Indicator(Indicator::POWER, 5, - &WXStatusPanel::DrawPower); - power->text = "POWER"; - indicators.emplace_back(power); + power = GetPowerDevice(); + ind = new Indicator(Indicator::POWER, 5, + &WXStatusPanel::DrawPower, "POWER"); + indicators.emplace_back(ind); // テスト用 if (__predict_false(0||(bool)*gHostInfo)) { @@ -356,19 +390,21 @@ WXStatusPanel::UpdateStat() }; // 電源オンか - MODIFY(ispower, gPower->IsPower()); - MODIFY(powerled, gPower->GetPowerLED()); + MODIFY(ispower, power->IsPower()); + MODIFY(powerled, power->GetPowerLED()); // パフォーマンスカウンタ - MODIFY(perf_mode, gSync->GetRunMode()); - MODIFY(perf_rate, gSync->GetPerfCounter()); + MODIFY(perf_mode, syncer->GetRunMode()); + MODIFY(perf_rate, syncer->GetPerfCounter()); // SCSI アクセス - MODIFY(scsi_bsy, scsibus->GetBSY()); - // 転送フェーズで DataOut の時だけ書き込みとみなす - bool out = (scsibus->GetPhase() == SCSI::Phase::Transfer) - && (scsibus->GetXfer() == SCSI::XferPhase::DataOut); - MODIFY(scsi_out, out); + if ((bool)scsibus) { + MODIFY(scsi_bsy, scsibus->GetBSY()); + // 転送フェーズで DataOut の時だけ書き込みとみなす + bool out = (scsibus->GetPhase() == SCSI::Phase::Transfer) + && (scsibus->GetXfer() == SCSI::XferPhase::DataOut); + MODIFY(scsi_out, out); + } // ネットワーク // パケット数が変化したとき、 @@ -380,15 +416,15 @@ WXStatusPanel::UpdateStat() } // FD - if (gFDC) { - const std::vector& fdd_vector = gFDC->GetFDD(); - for (const auto fdd : fdd_vector) { - if (fdd) { - int unit = fdd->GetUnitNo(); - MODIFY(fd_access_led[unit], fdd->GetAccessLED()); - MODIFY(fd_eject_led[unit], fdd->GetEjectLED()); - } - } + for (const auto fdd : fdd_vector) { + int unit = fdd->GetUnitNo(); + MODIFY(fdstat[unit].access_led, fdd->GetAccessLED()); + MODIFY(fdstat[unit].eject_led, fdd->GetEjectLED()); + } + + // NEWS LED + if (newsctlr) { + MODIFY(newsled, newsctlr->GetLED()); } // 電源 @@ -446,7 +482,7 @@ WXStatusPanel::DrawPerf(const Indicator // パフォーマンス表示は // o 高速モード指示中なら倍率表記 (115% なら 1.2x) // o 通常モード指示中ならパーセント表記 - if ((perf_mode & Sync::SCHED_SYNC) == 0) { + if ((perf_mode & Syncer::SCHED_SYNC) == 0) { // 高速モード指示 if (perf_mode == 0) { // 高速走行中 @@ -555,9 +591,7 @@ WXStatusPanel::DrawNet(const Indicator * void WXStatusPanel::DrawFD(const Indicator *ind) { - BitmapI8 accmark; Rect iconrect; - const uint8 *src; Color pal[3]; enum { BG = 0, @@ -570,7 +604,7 @@ WXStatusPanel::DrawFD(const Indicator *i const Rect& rect = ind->rect; pal[BG] = BGPANEL; - if (fd_loaded[unit]) { + if (fdstat[unit].loaded) { pal[FG] = UD_BLACK; } else { pal[FG] = UD_GREY; @@ -587,7 +621,7 @@ WXStatusPanel::DrawFD(const Indicator *i iconrect.h = font_height - 2; bitmap.DrawRect(pal[FG], iconrect); // ディスク挿入(取り出し可)なら黄緑点灯 - if (fd_eject_led[unit]) { + if (fdstat[unit].eject_led) { iconrect.x += 1; iconrect.y += 1; iconrect.w -= 2; @@ -596,24 +630,13 @@ WXStatusPanel::DrawFD(const Indicator *i } // その後で 3,4文字目の空き地に丸いインジケータを描画。 - switch (font_height) { - case 12: - src = AccessMark12; - break; - case 16: - src = AccessMark16; - break; - default: - PANIC("Unexpected font_height=%d", font_height); - } - accmark.Create(src, font_height, font_height); int dx = rect.x + 2 + font_width * 3; int dy = rect.y + 2; // アクセス LED はディスク非挿入時に点滅するケースがあって、 // その場合、フチがグレーのまま中を黄緑で塗りつぶすのは見えづらいので // 中を塗りつぶす時はフチを濃くしたほうがいい。 - switch (fd_access_led[unit]) { + switch (fdstat[unit].access_led) { case FDDDevice::LED::GREEN: pal[FG] = UD_BLACK; pal[IN] = UD_YELLOW_GREEN; @@ -626,7 +649,7 @@ WXStatusPanel::DrawFD(const Indicator *i pal[IN] = pal[BG]; break; } - bitmap.DrawBitmap(dx, dy, accmark, pal); + bitmap.DrawBitmap(dx, dy, *accmark, pal); } /*static*/ const uint8 @@ -663,6 +686,61 @@ WXStatusPanel::AccessMark16[] = { 0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, }; +/*static*/ const uint8 +WXStatusPanel::AccessMark24[] = { + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, 0,1,1,1,1,1,1,0, 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,1, 1,2,2,2,2,2,2,1, 1,0,0,0,0,0,0,0, + 0,0,0,0,0,1,1,2, 2,2,2,2,2,2,2,2, 2,1,1,0,0,0,0,0, + 0,0,0,0,1,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,1,0,0,0,0, + 0,0,0,1,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,1,0,0,0, + 0,0,0,1,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,1,0,0,0, + 0,0,1,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,1,0,0, + 0,0,1,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,1,0,0, + 0,1,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,1,0, + 0,1,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,1,0, + 0,1,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,1,0, + 0,1,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,1,0, + 0,1,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,1,0, + 0,1,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,1,0, + 0,0,1,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,1,0,0, + 0,0,1,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,1,0,0, + 0,0,0,1,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,1,0,0,0, + 0,0,0,1,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,1,0,0,0, + 0,0,0,0,1,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,1,0,0,0,0, + 0,0,0,0,0,1,1,2, 2,2,2,2,2,2,2,2, 2,1,1,0,0,0,0,0, + 0,0,0,0,0,0,0,1, 1,2,2,2,2,2,2,1, 1,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, 0,1,1,1,1,1,1,0, 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, +}; + +// NEWS LED1 +void +WXStatusPanel::DrawNewsLED1(const Indicator *ind) +{ + Color bg; + + if ((newsled & NewsCtlrDevice::LED_ORANGE) != 0) { + bg = UD_ORANGE; + } else { + bg = BGPANEL; + } + DrawTextLED(ind, UD_BLACK, bg); +} + +// NEWS LED2 +void +WXStatusPanel::DrawNewsLED2(const Indicator *ind) +{ + Color bg; + + if ((newsled & NewsCtlrDevice::LED_GREEN) != 0) { + bg = UD_GREEN; + } else { + bg = BGPANEL; + } + DrawTextLED(ind, UD_BLACK, bg); +} // 電源 LED void @@ -720,7 +798,7 @@ void WXStatusPanel::DClickPerf(const Indicator *ind) { // モードを切り替える - gSync->RequestFullSpeed(!gSync->GetFullSpeed()); + syncer->RequestFullSpeed(!syncer->GetFullSpeed()); } // コンテキストメニューイベント @@ -745,7 +823,8 @@ WXStatusPanel::ContextMenuCD(const Indic int scsiid = ind->GetSCSIID(); assertmsg(scsiid >= 0, "id=%d", ind->id); - auto menu = gMainFrame->CreateSCSIRemovableMenu(scsiid); + auto mainframe = dynamic_cast(GetParent()); + auto menu = mainframe->CreateSCSIRemovableMenu(scsiid); if (menu) { PopupMenu(menu); } @@ -758,7 +837,8 @@ WXStatusPanel::ContextMenuFD(const Indic int unit = ind->GetFDUnit(); assertmsg(unit >= 0, "id=%d", ind->id); - auto menu = gMainFrame->CreateFDMenu(unit); + auto mainframe = dynamic_cast(GetParent()); + auto menu = mainframe->CreateFDMenu(unit); if (menu) { PopupMenu(menu); } @@ -892,8 +972,8 @@ WXStatusPanel::OnFDDMediaChanged(wxComma // メディアのロード状態が変われば (再配置して) 再描画。 // 通常周期のタイマーによる更新チェックではメディア状態はチェックして // いないので、ここで自発的に行う。 - if (fd_loaded[unit] != new_loaded) { - fd_loaded[unit] = new_loaded; + if (fdstat[unit].loaded != new_loaded) { + fdstat[unit].loaded = new_loaded; LayoutIndicators(); Refresh();