--- nono/wx/wxstatuspanel.cpp 2026/04/29 17:05:16 1.1.1.6 +++ nono/wx/wxstatuspanel.cpp 2026/04/29 17:05:40 1.1.1.12 @@ -23,13 +23,145 @@ #include "wxmainframe.h" #include "wxmainview.h" #include "wxuimessage.h" -#include "wxversion.h" #include "fdc.h" #include "hostnet.h" #include "newsctlr.h" #include "power.h" -#include "spc.h" +#include "scsi.h" +#include "scsidomain.h" #include "syncer.h" +#include "virtio_block.h" +#include "virtio_scsi.h" + +// +// インジケータ情報 (ほぼ構造体) +// +class Indicator +{ + public: + // インジケータの識別子 + enum { + NONE = 0, + PERF, + POWER, + SCSI0, + SCSI1, + SCSI2, + SCSI3, + SCSI4, + SCSI5, + SCSI6, + SCSI7, + VBLK0, + VBLK1, + VBLK2, + VBLK3, + VBLK4, + VBLK5, + VBLK6, + VBLK7, + LAN0, + LAN1, + FDD0, + FDD1, + FDD2, + FDD3, + NEWSLED1, + NEWSLED2, + }; + protected: + using dispfunc_t = void (WXStatusPanel::*)(const Indicator *); + using eventfunc_t = void (WXStatusPanel::*)(const Indicator *); + public: + Indicator() { } + // 文字列の長さだけ指定する場合 + Indicator(int id_, dispfunc_t draw_, int minlen_, Status *stat_) { + id = id_; + draw = draw_; + stat = stat_; + minlen = minlen_; + } + // 文字列で指定する場合 + Indicator(int id_, dispfunc_t draw_, const std::string& text_, + Status *stat_) + : Indicator(id_, draw_, text_.length(), stat_) + { + text = text_; + } + virtual ~Indicator(); + + // インジケータ識別子 + int id {}; + + // 対応する状態 + Status *stat {}; + + // 枠内の最小文字列長。 + // 枠の大きさはこの文字列長と text.length() の長いほうで描画される。 + int minlen {}; + + // 表示する文字列。 + std::string text {}; + + // 描画関数 (必須) + dispfunc_t draw {}; + + // ダブルクリックの処理関数 (必要なら) + eventfunc_t dclick {}; + + // コンテキストメニューの処理関数 (必要なら) + eventfunc_t contextmenu {}; + + // 対応するデバイス (必要なら) + Device *dev {}; + + // ToolTip を表示するためのダミーパネル + wxPanel *panel {}; + + // 枠の位置と大きさは panel.GetRect() で取得できる (実行時に計算する) + Rect rect {}; + + public: + // SCSI なら SCSI ID を返す。そうでなければ -1 を返す。 + int GetSCSIID() const; + + // FDD ならユニット番号を返す。そうでなければ -1 を返す。 + int GetFDUnit() const; +}; + +// デストラクタ +Indicator::~Indicator() +{ +} + +// SCSI なら SCSI ID を返す。そうでなければ -1 を返す。 +int +Indicator::GetSCSIID() const +{ + int scsiid = id - SCSI0; + if (0 <= scsiid && scsiid <= 7) { + return scsiid; + } else { + return -1; + } +} + +// FDD ならユニット番号を返す。そうでなければ -1 を返す。 +int +Indicator::GetFDUnit() const +{ + int unit = id - FDD0; + if (0 <= unit && unit <= 3) { + return unit; + } else { + return -1; + } +} + + +// +// ステータスパネル +// wxBEGIN_EVENT_TABLE(WXStatusPanel, inherited) EVT_CLOSE(WXStatusPanel::OnClose) @@ -52,8 +184,13 @@ WXStatusPanel::WXStatusPanel(wxWindow *p : inherited(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, STATUS_PANEL_STYLE) { + SetName("WXStatusPanel"); + timer.SetOwner(this); + power = GetPowerDevice(); + syncer = GetSyncer(); + // インジケータ用のパラメータを用意。 InitIndicators(); @@ -71,6 +208,8 @@ WXStatusPanel::WXStatusPanel(wxWindow *p mainview); Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(WXMainView::OnKeyDown), NULL, mainview); + Connect(wxEVT_CHAR, wxKeyEventHandler(WXMainView::OnChar), NULL, + mainview); // VM からの通知を受け取る WXUIMessage::Connect(UIMessage::SCSI_MEDIA_CHANGE, this, @@ -190,30 +329,288 @@ WXStatusPanel::OnTimer(wxTimerEvent& eve } } -static const std::vector data = { - 0x0b, 0x06, 0x0b, 0x06, 0x00, 0x4c, 0x55, 0x4e, 0x41, 0x74, - 0x69, 0x63, 0x20, 0x54, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x72, +// store に value を代入。更新されていれば true を返す。 +// value は引数に渡す時に一度だけ評価される。 +#define MODIFY(store, value_) ({ \ + bool mod_; \ + decltype(value_) value = value_; \ + if (store != value) { \ + store = value; \ + mod_ = true; \ + } else { \ + mod_ = false; \ + } \ + mod_; /* return value */ \ +}) + +// +// インジケータ用の情報 +// +class Status +{ + public: + virtual ~Status(); + + // 情報取得メソッド + virtual bool Poll() = 0; +}; + +// デストラクタ +Status::~Status() +{ +} + +// Read/Write が別の3値タイプのアクセスインジケータ用 +enum class RWStatus : uint8 { + None = 0, + Read = 1, + Write = 2, }; +// +// SCSI 情報 (Bus/VirtIO 共通) +// +class StatusSCSI : public Status +{ + public: + std::array active {}; +}; + +// +// SCSIBus 情報 +// +class StatusSCSIBus : public StatusSCSI +{ + public: + StatusSCSIBus(SCSIBus *scsibus_) { + scsibus = scsibus_; + } + ~StatusSCSIBus() override; + + bool Poll() override { + uint8 bsy = scsibus->GetBSY(); + // 転送フェーズで DataOut の時だけ書き込みとみなす + bool out = (scsibus->GetPhase() == SCSI::Phase::Transfer) + && (scsibus->GetXfer() == SCSI::XferPhase::DataOut); + + bool mod = false; + for (uint id = 0; id < 8; id++) { + RWStatus newactive; + if (__predict_false((bsy & (1U << id)) != 0)) { + if (out) { + newactive = RWStatus::Write; + } else { + newactive = RWStatus::Read; + } + } else { + newactive = RWStatus::None; + } + mod |= MODIFY(active[id], newactive); + } + return mod; + } + + private: + SCSIBus *scsibus {}; +}; + +// デストラクタ +StatusSCSIBus::~StatusSCSIBus() +{ +} + +// +// VirtIOSCSI 情報 +// +class StatusVSCSI : public StatusSCSI +{ + public: + StatusVSCSI(VirtIOSCSIDevice *dev_) { + dev = dev_; + } + ~StatusVSCSI() override = default; + + bool Poll() override { + std::array newacc; + dev->GetAccess(&newacc); + bool mod = false; + for (uint id = 0; id < 8; id++) { + bool rmod = MODIFY(access[id * 2 + 0], newacc[id * 2 + 0]); + bool wmod = MODIFY(access[id * 2 + 1], newacc[id * 2 + 1]); + + RWStatus newactive; + if (wmod) { + newactive = RWStatus::Write; + } else if (rmod) { + newactive = RWStatus::Read; + } else { + newactive = RWStatus::None; + } + mod |= MODIFY(active[id], newactive); + } + return mod; + } + + std::array access {}; + + private: + VirtIOSCSIDevice *dev {}; +}; + +// +// VirtIOBlock 情報 +// +class StatusVBlk : public Status +{ + public: + StatusVBlk(VirtIOBlockDevice *dev_) { + dev = dev_; + } + ~StatusVBlk() override; + + bool Poll() override { + bool rmod = MODIFY(access_read, dev->GetAccessRead()); + bool wmod = MODIFY(access_write, dev->GetAccessWrite()); + RWStatus newactive; + if (wmod) { + newactive = RWStatus::Write; + } else if (rmod) { + newactive = RWStatus::Read; + } else { + newactive = RWStatus::None; + } + return MODIFY(active, newactive); + } + + // アクセス状況 + uint32 access_read {}; + uint32 access_write {}; + RWStatus active {}; + + private: + VirtIOBlockDevice *dev {}; +}; + +// デストラクタ +StatusVBlk::~StatusVBlk() +{ +} + +// +// ネットワーク情報 +// +class StatusNet : public Status +{ + public: + StatusNet(HostNetDevice *hostnet_) { + hostnet = hostnet_; + } + ~StatusNet() override; + + bool Poll() override { + // パケット数が変化したとき、および + // その変化を監視しているアクティブ状態が変化したときに + // 変更があったとしたいので二重になっている。 + bool tx_mod = MODIFY(tx_pkts, hostnet->GetTXPkts()); + bool rx_mod = MODIFY(rx_pkts, hostnet->GetRXPkts()); + + bool mod = false; + mod |= MODIFY(tx_active, tx_mod); + mod |= MODIFY(rx_active, rx_mod); + return mod; + } + + bool enable {}; + uint64 tx_pkts {}; + uint64 rx_pkts {}; + bool tx_active {}; + bool rx_active {}; + + private: + HostNetDevice *hostnet {}; +}; + +// デストラクタ +StatusNet::~StatusNet() +{ +} + +// +// FDD 情報 +// +class StatusFDD : public Status +{ + public: + StatusFDD(FDDDevice *fdd_) { + fdd = fdd_; + } + ~StatusFDD() override; + + bool Poll() override { + bool mod = false; + mod |= MODIFY(access_led, fdd->GetAccessLED()); + mod |= MODIFY(eject_led, fdd->GetEjectLED()); + return mod; + } + + FDDDevice::LED access_led {}; // アクセス LED の状態 + bool eject_led {}; // イジェクト LED 点灯なら true + private: + FDDDevice *fdd {}; +}; + +// デストラクタ +StatusFDD::~StatusFDD() +{ +} + +// +// NEWS の LED 情報 +// +class StatusNEWS : public Status +{ + public: + StatusNEWS(NewsCtlrDevice *newsctlr_) { + newsctlr = newsctlr_; + } + ~StatusNEWS() override; + + bool Poll() override { + return MODIFY(led, newsctlr->GetLED()); + } + + uint led {}; + private: + NewsCtlrDevice *newsctlr {}; +}; + +// デストラクタ +StatusNEWS::~StatusNEWS() +{ +} + + // インジケータの初期化 void WXStatusPanel::InitIndicators() { + Status *stat; Indicator *ind; // パフォーマンスカウンタ - syncer = GetSyncer(); - ind = new Indicator(Indicator::PERF, 8/* >>>9999% */, - &WXStatusPanel::DrawPerf); + ind = new Indicator(Indicator::PERF, &WXStatusPanel::DrawPerf, + 8/* >>>9999% */, NULL); ind->dclick = &WXStatusPanel::DClickPerf; indicators.emplace_back(ind); // SCSI - // SPC の接続済みデバイスリストから取得。 - // (ホストアダプタ2つ目のことは考えてない) - auto spc = gMainApp.FindObject(OBJ_SPC); - if (spc) { - const std::vector& conn = spc->GetConnectedDevices(); + // 接続済みデバイスリストから取得。 + auto scsibus = gMainApp.FindObject(OBJ_SCSIBUS); + if (scsibus) { + stat = new StatusSCSIBus(scsibus); + stats.emplace_back(stat); + + const auto& conn = scsibus->GetDomain()->GetConnectedDevices(); for (const auto& dev : conn) { SCSI::DevType devtype = dev->GetDevType(); if (devtype == SCSI::DevType::Initiator) { @@ -222,11 +619,56 @@ WXStatusPanel::InitIndicators() int scsiid = dev->GetMyID(); // 文字列は OnSCSIMediaChanged() でセットする。 - ind = new Indicator(Indicator::SCSI0 + scsiid, 3, - &WXStatusPanel::DrawSCSI); + ind = new Indicator(Indicator::SCSI0 + scsiid, + &WXStatusPanel::DrawSCSI, 3, stat); ind->contextmenu = &WXStatusPanel::ContextMenuCD; ind->dev = dev; ind->panel = new wxPanel(this); + ind->panel->SetName("WXStatusPanel.SCSI"); + // このパネルがフォーカスを受け取らないようにする。 + // StatusPanel がフォーカスを持っていてもキー入力を MainFrame に渡す + // ようにしているため、StatusPanel のフォーカスを奪ってはいけない。 + ind->panel->SetCanFocus(false); + + indicators.emplace_back(ind); + } + } + + // VirtIOBlock + for (int i = 0; i < 8; i++) { + auto dev = gMainApp.FindObject(OBJ_VIRTIO_BLOCK(i)); + if (dev) { + stat = new StatusVBlk(dev); + stats.emplace_back(stat); + + std::string label = string_format("VB%u", i); + if (dev->GetWriteMode() == SCSIDisk::RW::WriteIgnore) { + label += "\x02\x03"; + } + ind = new Indicator(Indicator::VBLK0 + i, &WXStatusPanel::DrawVBlk, + label, stat); + ind->dev = dev; + indicators.emplace_back(ind); + } + } + + // VirtIOSCSI + auto vscsi = gMainApp.FindObject(OBJ_VIRTIO_SCSI); + if (vscsi) { + stat = new StatusVSCSI(vscsi); + stats.emplace_back(stat); + + const auto& conn = vscsi->GetDomain()->GetConnectedDevices(); + for (const auto& dev : conn) { + int scsiid = dev->GetMyID(); + + // 文字列は OnSCSIMediaChanged() でセットする。 + ind = new Indicator(Indicator::SCSI0 + scsiid, + &WXStatusPanel::DrawSCSI, 3, stat); + ind->contextmenu = &WXStatusPanel::ContextMenuCD; + ind->dev = dev; + ind->panel = new wxPanel(this); + ind->panel->SetName("WXStatusPanel.VSCSI"); // このパネルがフォーカスを受け取らないようにする。 // StatusPanel がフォーカスを持っていてもキー入力を MainFrame に渡す // ようにしているため、StatusPanel のフォーカスを奪ってはいけない。 @@ -234,40 +676,50 @@ WXStatusPanel::InitIndicators() indicators.emplace_back(ind); } - // BSY 取得用 - scsibus = spc->GetSCSIBus(); } // ネットワーク - hostnet = gMainApp.FindObject(OBJ_HOSTNET); - if (hostnet) { - if (hostnet->GetDriverName() == "none") { - net_ok = DISABLE; - } else { - net_ok = ENABLE; + for (int i = 0; i < 2; i++) { + auto hostnet = gMainApp.FindObject(OBJ_HOSTNET(i)); + if (hostnet) { + auto statnet = new StatusNet(hostnet); + stat = statnet; + stats.emplace_back(stat); + + if (hostnet->GetDriverName() == "none") { + statnet->enable = false; + } else { + statnet->enable = true; + } + // \x1e は上向き矢印、\x1f は下向き矢印。 + // ラベルは結局機種で変わる… + std::string label; + if (gMainApp.IsX68030()) { + label = string_format("LAN%d\x1e\x1f", i); + } else { + label = "LAN\x1e\x1f"; + } + ind = new Indicator(Indicator::LAN0 + i, &WXStatusPanel::DrawNet, + label, stat); + indicators.emplace_back(ind); } - // \x1e は上向き矢印、\x1f は下向き矢印 - ind = new Indicator(Indicator::LAN, 5, - &WXStatusPanel::DrawNet, "LAN\x1e\x1f"); - indicators.emplace_back(ind); - } else { - net_ok = NOT_AVAILABLE; } // FD for (int unit = 0; unit < FDCDevice::MAX_DRIVE; unit++) { auto fdd = gMainApp.FindObject(OBJ_FDD(unit)); if (fdd) { - // 存在するドライブのリスト - fdd_vector.push_back(fdd); + stat = new StatusFDD(fdd); + stats.emplace_back(stat); // 文字列は OnFDDMediaChanged() でセットする。 - ind = new Indicator(Indicator::FDD0 + unit, 7, - &WXStatusPanel::DrawFD); + ind = new Indicator(Indicator::FDD0 + unit, + &WXStatusPanel::DrawFD, 7, stat); ind->contextmenu = &WXStatusPanel::ContextMenuFD; ind->dev = fdd; ind->panel = new wxPanel(this); + ind->panel->SetName("WXStatusPanel.FD"); // フォーカスを受け取らない。少し上の CD のところ参照。 ind->panel->SetCanFocus(false); @@ -276,39 +728,24 @@ WXStatusPanel::InitIndicators() } // NEWS の LED (2->1 の順で並べる) - newsctlr = gMainApp.FindObject(OBJ_NEWSCTLR); + auto newsctlr = gMainApp.FindObject(OBJ_NEWSCTLR); if (newsctlr) { - ind = new Indicator(Indicator::NEWSLED2, 2, - &WXStatusPanel::DrawNewsLED2, "LED2"); + stat = new StatusNEWS(newsctlr); + stats.emplace_back(stat); + + ind = new Indicator(Indicator::NEWSLED2, &WXStatusPanel::DrawNewsLED2, + "LED2", stat); indicators.emplace_back(ind); - ind = new Indicator(Indicator::NEWSLED1, 2, - &WXStatusPanel::DrawNewsLED1, "LED1"); + ind = new Indicator(Indicator::NEWSLED1, &WXStatusPanel::DrawNewsLED1, + "LED1", stat); indicators.emplace_back(ind); } // 電源 LED - power = GetPowerDevice(); - ind = new Indicator(Indicator::POWER, 5, - &WXStatusPanel::DrawPower, "POWER"); + ind = new Indicator(Indicator::POWER, &WXStatusPanel::DrawPower, + "POWER", NULL); indicators.emplace_back(ind); - - // テスト用 - if (__predict_false(0||(bool)*gHostInfo)) { - std::string s((const char *)GetParent()->GetLabel().mb_str()); - int i = 0; - for (; i < 5; i++) { - s[i] += data[i]; - } - for (; i < 9; i++) { - if (s[i] != data[i]) - return; - } - for (; i < data.size(); i++) { - s.insert(s.begin() + i, data[i]); - } - GetParent()->SetLabel(s); - } } // インジケータのレイアウト @@ -378,58 +815,22 @@ WXStatusPanel::LayoutIndicators() bool WXStatusPanel::UpdateStat() { - bool updated = false; + bool mod = false; - // store に value を代入。更新されていれば updated を立てる。 - // value は一度だけ評価される。 - auto MODIFY = [&](auto& store, auto value) { - bool rv = store != value; - updated |= rv; - store = value; - return rv; - }; - - // 電源オンか - MODIFY(ispower, power->IsPower()); - MODIFY(powerled, power->GetPowerLED()); + // 電源オン + mod |= MODIFY(ispower, power->IsPower()); + mod |= MODIFY(powerled, power->GetPowerLED()); // パフォーマンスカウンタ - MODIFY(perf_mode, syncer->GetRunMode()); - MODIFY(perf_rate, syncer->GetPerfCounter()); - - // SCSI アクセス - 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); - } + mod |= MODIFY(perf_mode, syncer->GetRunMode()); + mod |= MODIFY(perf_rate, syncer->GetPerfCounter()); - // ネットワーク - // パケット数が変化したとき、 - // およびその変化を監視しているアクティブ状態が変化したとき - // に変更があったとしたいので二重になっている - if (net_ok != NOT_AVAILABLE) { - MODIFY(net_tx_active, MODIFY(net_tx_pkts, hostnet->GetTXPkts())); - MODIFY(net_rx_active, MODIFY(net_rx_pkts, hostnet->GetRXPkts())); - } - - // FD - for (const auto fdd : fdd_vector) { - int unit = fdd->GetUnitNo(); - MODIFY(fdstat[unit].access_led, fdd->GetAccessLED()); - MODIFY(fdstat[unit].eject_led, fdd->GetEjectLED()); + // それ以外 + for (const auto stat : stats) { + mod |= stat->Poll(); } - // NEWS LED - if (newsctlr) { - MODIFY(newsled, newsctlr->GetLED()); - } - - // 電源 - - return updated; + return mod; } // 描画本体 @@ -482,7 +883,7 @@ WXStatusPanel::DrawPerf(const Indicator // パフォーマンス表示は // o 高速モード指示中なら倍率表記 (115% なら 1.2x) // o 通常モード指示中ならパーセント表記 - if ((perf_mode & Syncer::SCHED_SYNC) == 0) { + if ((perf_mode & Syncer::SYNCMODE_SYNC) == 0) { // 高速モード指示 if (perf_mode == 0) { // 高速走行中 @@ -492,13 +893,22 @@ WXStatusPanel::DrawPerf(const Indicator } // 倍率表記は1桁少ないので、表示用に最下位桁を四捨五入 - int rate = perf_rate + 5; - snprintf(text, sizeof(text), "%2d.%1dx", - (rate / 100), (rate % 100) / 10); + uint rate = perf_rate + 5; + if (rate < 100 * 100) { + // 2桁倍までなら "99.9x" のように小数以下1桁まで。 + snprintf(text, sizeof(text), "%2u.%1ux", + (rate / 100), (rate % 100) / 10); + } else if (rate < 10000 * 100) { + // 3桁倍、4桁倍だと整数部のみ。"9999x" + snprintf(text, sizeof(text), "%4ux", rate / 100); + } else { + // どうする? + strlcpy(text, "9999x", sizeof(text)); + } } else { // 通常モード指示 ffmark = " "; - snprintf(text, sizeof(text), "%4d%%", perf_rate); + snprintf(text, sizeof(text), "%4u%%", perf_rate); } DrawStringSJIS(UD_RED, rect.x + 2, rect.y + 2, ffmark); @@ -510,27 +920,44 @@ WXStatusPanel::DrawPerf(const Indicator void WXStatusPanel::DrawSCSI(const Indicator *ind) { + const StatusSCSI *stat = dynamic_cast(ind->stat); Color fg; Color bg; int scsiid; - uint idmask; scsiid = ind->GetSCSIID(); assertmsg(scsiid >= 0, "id=%d", ind->id); - idmask = 1U << scsiid; - if ((scsi_loaded & idmask) != 0) { + if (scsi_loaded[scsiid]) { fg = UD_BLACK; } else { fg = UD_GREY; } - if ((scsi_bsy & idmask) != 0) { - if (scsi_out) { - bg = UD_RED; - } else { - bg = UD_YELLOW_GREEN; - } + if (stat->active[scsiid] == RWStatus::Write) { + bg = UD_RED; + } else if (stat->active[scsiid] == RWStatus::Read) { + bg = UD_YELLOW_GREEN; + } else { + bg = BGPANEL; + } + + DrawTextLED(ind, fg, bg); +} + +// VirtIOBlock デバイスのアクセスランプ。 +void +WXStatusPanel::DrawVBlk(const Indicator *ind) +{ + const StatusVBlk *stat = dynamic_cast(ind->stat); + Color fg; + Color bg; + + fg = UD_BLACK; + if (stat->active == RWStatus::Write) { + bg = UD_RED; + } else if (stat->active == RWStatus::Read) { + bg = UD_YELLOW_GREEN; } else { bg = BGPANEL; } @@ -542,13 +969,14 @@ WXStatusPanel::DrawSCSI(const Indicator void WXStatusPanel::DrawNet(const Indicator *ind) { + const StatusNet *stat = dynamic_cast(ind->stat); + const Rect& rect = ind->rect; Color fg; Color bg = BGPANEL; - const Rect& rect = ind->rect; - if (net_ok) { + if (stat->enable) { fg = UD_BLACK; - if (net_tx_active || net_rx_active) { + if (stat->tx_active || stat->rx_active) { bg = UD_YELLOW_GREEN; } } else { @@ -566,14 +994,14 @@ WXStatusPanel::DrawNet(const Indicator * auto c = ind->text[i]; switch (c) { case '\x1e': // 上向き矢印 - if (net_tx_active) { + if (stat->tx_active) { fg = UD_BLACK; } else { fg = UD_GREY; } break; case '\x1f': // 下向き矢印 - if (net_rx_active) { + if (stat->rx_active) { fg = UD_BLACK; } else { fg = UD_GREY; @@ -591,20 +1019,21 @@ WXStatusPanel::DrawNet(const Indicator * void WXStatusPanel::DrawFD(const Indicator *ind) { + const StatusFDD *stat = dynamic_cast(ind->stat); + const Rect& rect = ind->rect; Rect iconrect; Color pal[3]; + int unit; enum { BG = 0, FG, IN, }; - int unit; unit = ind->GetFDUnit(); - const Rect& rect = ind->rect; pal[BG] = BGPANEL; - if (fdstat[unit].loaded) { + if (fd_loaded[unit]) { pal[FG] = UD_BLACK; } else { pal[FG] = UD_GREY; @@ -621,7 +1050,7 @@ WXStatusPanel::DrawFD(const Indicator *i iconrect.h = font_height - 2; bitmap.DrawRect(pal[FG], iconrect); // ディスク挿入(取り出し可)なら黄緑点灯 - if (fdstat[unit].eject_led) { + if (stat->eject_led) { iconrect.x += 1; iconrect.y += 1; iconrect.w -= 2; @@ -636,7 +1065,7 @@ WXStatusPanel::DrawFD(const Indicator *i // アクセス LED はディスク非挿入時に点滅するケースがあって、 // その場合、フチがグレーのまま中を黄緑で塗りつぶすのは見えづらいので // 中を塗りつぶす時はフチを濃くしたほうがいい。 - switch (fdstat[unit].access_led) { + switch (stat->access_led) { case FDDDevice::LED::GREEN: pal[FG] = UD_BLACK; pal[IN] = UD_YELLOW_GREEN; @@ -649,7 +1078,7 @@ WXStatusPanel::DrawFD(const Indicator *i pal[IN] = pal[BG]; break; } - bitmap.DrawBitmap(dx, dy, *accmark, pal); + bitmap.DrawBitmapI8(dx, dy, *accmark, pal); } /*static*/ const uint8 @@ -718,9 +1147,10 @@ WXStatusPanel::AccessMark24[] = { void WXStatusPanel::DrawNewsLED1(const Indicator *ind) { + const StatusNEWS *stat = dynamic_cast(ind->stat); Color bg; - if ((newsled & NewsCtlrDevice::LED_ORANGE) != 0) { + if ((stat->led & NewsCtlrDevice::LED_ORANGE) != 0) { bg = UD_ORANGE; } else { bg = BGPANEL; @@ -732,9 +1162,10 @@ WXStatusPanel::DrawNewsLED1(const Indica void WXStatusPanel::DrawNewsLED2(const Indicator *ind) { + const StatusNEWS *stat = dynamic_cast(ind->stat); Color bg; - if ((newsled & NewsCtlrDevice::LED_GREEN) != 0) { + if ((stat->led & NewsCtlrDevice::LED_GREEN) != 0) { bg = UD_GREEN; } else { bg = BGPANEL; @@ -849,7 +1280,7 @@ void WXStatusPanel::OnSCSIMediaChanged(wxCommandEvent& event) { Indicator *ind = NULL; - uint8 new_loaded; + bool new_loaded; // 該当の Indicator を探す (見付かるはず) int scsiid = event.GetInt(); @@ -864,8 +1295,7 @@ WXStatusPanel::OnSCSIMediaChanged(wxComm const auto disk = dynamic_cast(ind->dev); // メディアの状態を一旦クリア - new_loaded = scsi_loaded; - new_loaded &= ~(1U << scsiid); + new_loaded = false; // ツールチップを設定 SCSI::DevType devtype = disk->GetDevType(); @@ -877,7 +1307,7 @@ WXStatusPanel::OnSCSIMediaChanged(wxComm tip += "-"; } else { tip += path; - new_loaded |= (1U << scsiid); + new_loaded = true; } switch (disk->GetWriteMode()) { case SCSIDisk::RW::ReadOnly: @@ -899,7 +1329,7 @@ WXStatusPanel::OnSCSIMediaChanged(wxComm // 無駄に幅を取らないためメディア挿入時のみ表示。 // MO のライトプロテクト表示は必要になったら考える…。 ind->text = string_format("%s%d", SCSI::GetDevTypeName(devtype), scsiid); - if ((new_loaded & (1U << scsiid))) { + if (new_loaded) { if (disk->GetWriteMode() == SCSIDisk::RW::WriteIgnore) { ind->text += "\x02\x03"; } @@ -908,8 +1338,8 @@ WXStatusPanel::OnSCSIMediaChanged(wxComm // メディアのロード状態が変われば (再配置して) 再描画。 // 通常周期のタイマーによる更新チェックではメディア状態はチェックして // いないので、ここで自発的に行う。 - if (scsi_loaded != new_loaded) { - scsi_loaded = new_loaded; + if (scsi_loaded[scsiid] != new_loaded) { + scsi_loaded[scsiid] = new_loaded; LayoutIndicators(); Refresh(); @@ -972,8 +1402,8 @@ WXStatusPanel::OnFDDMediaChanged(wxComma // メディアのロード状態が変われば (再配置して) 再描画。 // 通常周期のタイマーによる更新チェックではメディア状態はチェックして // いないので、ここで自発的に行う。 - if (fdstat[unit].loaded != new_loaded) { - fdstat[unit].loaded = new_loaded; + if (fd_loaded[unit] != new_loaded) { + fd_loaded[unit] = new_loaded; LayoutIndicators(); Refresh(); @@ -991,32 +1421,3 @@ WXStatusPanel::OnLEDChanged(wxCommandEve Refresh(); } } - - -// -// インジケータ情報 -// - -// SCSI なら SCSI ID を返す。そうでなければ -1 を返す。 -int -Indicator::GetSCSIID() const -{ - int scsiid = id - SCSI0; - if (0 <= scsiid && scsiid <= 7) { - return scsiid; - } else { - return -1; - } -} - -// FDD ならユニット番号を返す。そうでなければ -1 を返す。 -int -Indicator::GetFDUnit() const -{ - int unit = id - FDD0; - if (0 <= unit && unit <= 3) { - return unit; - } else { - return -1; - } -}