--- nono/wx/wxstatuspanel.cpp 2026/04/29 17:05:40 1.1.1.12 +++ nono/wx/wxstatuspanel.cpp 2026/04/29 17:05:53 1.1.1.15 @@ -25,6 +25,7 @@ #include "wxuimessage.h" #include "fdc.h" #include "hostnet.h" +#include "mpu.h" #include "newsctlr.h" #include "power.h" #include "scsi.h" @@ -166,7 +167,6 @@ Indicator::GetFDUnit() const wxBEGIN_EVENT_TABLE(WXStatusPanel, inherited) EVT_CLOSE(WXStatusPanel::OnClose) EVT_SHOW(WXStatusPanel::OnShow) - EVT_SIZE(WXStatusPanel::OnSize) EVT_TIMER(wxID_ANY, WXStatusPanel::OnTimer) EVT_LEFT_DCLICK(WXStatusPanel::OnLeftDClick) EVT_CONTEXT_MENU(WXStatusPanel::OnContextMenu) @@ -194,6 +194,7 @@ WXStatusPanel::WXStatusPanel(wxWindow *p // インジケータ用のパラメータを用意。 InitIndicators(); + SetAutoLayout(true); FontChanged(); // キー入力イベントをメインビューに転送。 @@ -237,6 +238,28 @@ WXStatusPanel::~WXStatusPanel() wxCommandEventHandler(WXStatusPanel::OnLEDChanged)); } +// 初期化 +void +WXStatusPanel::Init() +{ + // ここで最初に一回、全メディアの状態更新を能動的に行う。 + for (const auto ind : indicators) { + int id; + id = ind->GetSCSIID(); + if (id >= 0) { + wxCommandEvent event(NONO_EVT_UIMESSAGE); + event.SetInt(id); + OnSCSIMediaChanged(event); + } + id = ind->GetFDUnit(); + if (id >= 0) { + wxCommandEvent event(NONO_EVT_UIMESSAGE); + event.SetInt(id); + OnFDDMediaChanged(event); + } + } +} + // クローズイベント void WXStatusPanel::OnClose(wxCloseEvent& event) @@ -291,33 +314,19 @@ WXStatusPanel::FontChanged() } accmark.reset(new BitmapI8(src, font_height, font_height)); - // インジケータを再レイアウト - LayoutIndicators(); - - // コントロールの大きさを変更 - wxSize size = GetClientSize(); - size.y = font_height + 8; - SetClientSize(size); + Fit(); } -// サイズ変更イベント void -WXStatusPanel::OnSize(wxSizeEvent& event) +WXStatusPanel::Fit() { - // Mac ではウィンドウ作成時に 0 以下の値が来ることがある。 - // GTK では 1 で来ることがある。 - const wxSize& size = event.GetSize(); - if (size.x <= 1 || size.y <= 1) { - return; - } - - // 親クラス - inherited::OnSize(event); + wxSize size = LayoutIndicators(); - LayoutIndicators(); + // バックバッファのサイズを固定。 + SetMinBitmapSize(size); - // 再描画を指示 - Refresh(); + SetMinSize(size); + SetSize(size); } // タイマーイベント @@ -598,8 +607,12 @@ WXStatusPanel::InitIndicators() Indicator *ind; // パフォーマンスカウンタ - ind = new Indicator(Indicator::PERF, &WXStatusPanel::DrawPerf, - 8/* >>>9999% */, NULL); + // 0123456789012345 + // >>> 99.9x 100MHz + auto mpu = gMainApp.FindObject(OBJ_MPU); + assert(mpu); + clock_khz = mpu->GetClockSpeed(); + ind = new Indicator(Indicator::PERF, &WXStatusPanel::DrawPerf, 15, NULL); ind->dclick = &WXStatusPanel::DClickPerf; indicators.emplace_back(ind); @@ -618,9 +631,14 @@ WXStatusPanel::InitIndicators() } int scsiid = dev->GetMyID(); - // 文字列は OnSCSIMediaChanged() でセットする。 + std::string label = string_format("%s%d", + SCSI::GetDevTypeName(devtype), scsiid); + const auto disk = dynamic_cast(dev); + if (disk && disk->GetWriteMode() == SCSIDisk::RW::WriteIgnore) { + label += "\x02\x03"; + } ind = new Indicator(Indicator::SCSI0 + scsiid, - &WXStatusPanel::DrawSCSI, 3, stat); + &WXStatusPanel::DrawSCSI, label, stat); ind->contextmenu = &WXStatusPanel::ContextMenuCD; ind->dev = dev; ind->panel = new wxPanel(this); @@ -660,11 +678,17 @@ WXStatusPanel::InitIndicators() const auto& conn = vscsi->GetDomain()->GetConnectedDevices(); for (const auto& dev : conn) { + SCSI::DevType devtype = dev->GetDevType(); int scsiid = dev->GetMyID(); - // 文字列は OnSCSIMediaChanged() でセットする。 + std::string label = string_format("%s%d", + SCSI::GetDevTypeName(devtype), scsiid); + const auto disk = dynamic_cast(dev); + if (disk && disk->GetWriteMode() == SCSIDisk::RW::WriteIgnore) { + label += "\x02\x03"; + } ind = new Indicator(Indicator::SCSI0 + scsiid, - &WXStatusPanel::DrawSCSI, 3, stat); + &WXStatusPanel::DrawSCSI, label, stat); ind->contextmenu = &WXStatusPanel::ContextMenuCD; ind->dev = dev; ind->panel = new wxPanel(this); @@ -712,10 +736,15 @@ WXStatusPanel::InitIndicators() stat = new StatusFDD(fdd); stats.emplace_back(stat); + // 後ろの4文字分のスペースは LED アイコン用の場所取り。 + std::string label = string_format("FD%d ", fdd->GetUnitNo()); + if (fdd->GetWriteMode() == FDDDevice::RW::WriteIgnore) { + label += "\x02\x03"; + } + // 文字列は OnFDDMediaChanged() でセットする。 ind = new Indicator(Indicator::FDD0 + unit, - &WXStatusPanel::DrawFD, 7, stat); - + &WXStatusPanel::DrawFD, label, stat); ind->contextmenu = &WXStatusPanel::ContextMenuFD; ind->dev = fdd; ind->panel = new wxPanel(this); @@ -748,8 +777,10 @@ WXStatusPanel::InitIndicators() indicators.emplace_back(ind); } -// インジケータのレイアウト -void +// インジケータの配置位置を求める。 +// ind->rect を更新するがここで描画とかはしない。 +// 戻り値はインジケータの配置に必要な最小サイズ。 +wxSize WXStatusPanel::LayoutIndicators() { int x; @@ -780,23 +811,39 @@ WXStatusPanel::LayoutIndicators() x += 1; // この x が最小サイズなのでこれをコントロールに設定。 - // (コントロールのサイズは WXMainFrame::Layout() が設定する) - SetMinClientSize(wxSize(x, font_height + 8)); + wxSize size(x, h + 2 + 2); + return size; +} + +// レイアウト +bool +WXStatusPanel::Layout() +{ + if (indicators.empty()) { + return false; + } - // 全員を一旦右寄せ - wxSize sz = GetClientSize(); - int offsetx = sz.x - x; + // レイアウトの計算はビットマップサイズに対して行う。 + // 起動直後に何かの拍子で随分小さいサイズにリサイズされることがあったり + // また実画面が小さくてそもそも入り切らないような場合でも、 + // ビットマップは常に最低限描画できるサイズを保証してあるので。 + // それを画面に転送しても見た目は事故るがとりあえず死にはしないので。 + wxSize size(bitmap.GetWidth(), bitmap.GetHeight()); + + // 配置情報をリセット。(左寄せ相当になる) + wxSize minsize = LayoutIndicators(); + + // 全員を一旦右寄せ。 + int offsetx = size.x - minsize.x; for (auto ind : indicators) { ind->rect.Offset(offsetx, 0); } // そのうちパフォーマンスカウンタだけ中央寄せまで戻す - if (indicators.size() > 0) { - auto p = indicators.front(); - x = (sz.x / 2) - (p->rect.w / 2); - if (p->rect.x > x) { - p->rect.x = x; - } + auto perf = indicators.front(); + int x = (size.x / 2) - (perf->rect.w / 2); + if (perf->rect.x > x) { + perf->rect.x = x; } // パネルをもっていれば、パネルをその位置に(再)設定。 @@ -808,6 +855,7 @@ WXStatusPanel::LayoutIndicators() } refresh_background = true; + return true; } // 状態をチェック。 @@ -843,13 +891,13 @@ WXStatusPanel::Draw() if (refresh_background) { refresh_background = false; bitmap.Fill(BGPANEL); - } - // なんとなく見栄えのため上下に薄い線を引く。 - // 四方を線で囲むとオーバーレイウィンドウのように見えるので上下だけ。 - wxSize size = GetSize(); - bitmap.DrawLineH(UD_GREY, 0, 0, size.x); - bitmap.DrawLineH(UD_GREY, 0, size.y - 1, size.x); + // なんとなく見栄えのため上下に薄い線を引く。 + // 四方を線で囲むとオーバーレイウィンドウのように見えるので上下だけ。 + wxSize size = GetSize(); + bitmap.DrawLineH(UD_GREY, 0, 0, size.x); + bitmap.DrawLineH(UD_GREY, 0, size.y - 1, size.x); + } // 各インジケータを描画 for (auto ind : indicators) { @@ -911,6 +959,10 @@ WXStatusPanel::DrawPerf(const Indicator snprintf(text, sizeof(text), "%4u%%", perf_rate); } + // クロックスピード(MHz)も四捨五入。 + uint eff_khz = (clock_khz * perf_rate + 50) / 100; + snprintf(text + 5, sizeof(text) - 5, "%4uMHz", (eff_khz + 500) / 1000); + DrawStringSJIS(UD_RED, rect.x + 2, rect.y + 2, ffmark); DrawStringSJIS(rect.x + 2 + font_width * 3, rect.y + 2, text); } @@ -1229,7 +1281,7 @@ void WXStatusPanel::DClickPerf(const Indicator *ind) { // モードを切り替える - syncer->RequestFullSpeed(!syncer->GetFullSpeed()); + syncer->NotifyFullSpeed(!syncer->GetFullSpeed()); } // コンテキストメニューイベント @@ -1324,24 +1376,11 @@ WXStatusPanel::OnSCSIMediaChanged(wxComm } ind->panel->SetToolTip(tip); - // 書き込み無視だけ、これによって shutdown が必要かどうかという - // オペレーションに違いが出るため表示する。 - // 無駄に幅を取らないためメディア挿入時のみ表示。 - // MO のライトプロテクト表示は必要になったら考える…。 - ind->text = string_format("%s%d", SCSI::GetDevTypeName(devtype), scsiid); - if (new_loaded) { - if (disk->GetWriteMode() == SCSIDisk::RW::WriteIgnore) { - ind->text += "\x02\x03"; - } - } - // メディアのロード状態が変われば (再配置して) 再描画。 // 通常周期のタイマーによる更新チェックではメディア状態はチェックして // いないので、ここで自発的に行う。 if (scsi_loaded[scsiid] != new_loaded) { scsi_loaded[scsiid] = new_loaded; - - LayoutIndicators(); Refresh(); } } @@ -1390,22 +1429,11 @@ WXStatusPanel::OnFDDMediaChanged(wxComma } ind->panel->SetToolTip(tip); - ind->text = string_format("FD%d", fdd->GetUnitNo()); - // 書き込み無視だけ表示する。無駄に幅を取らないためメディア挿入時のみ表示。 - // 4文字分のマークの後ろに "WI" を追加。 - if (new_loaded) { - if (fdd->GetWriteMode() == FDDDevice::RW::WriteIgnore) { - ind->text += " \x02\x03"; - } - } - // メディアのロード状態が変われば (再配置して) 再描画。 // 通常周期のタイマーによる更新チェックではメディア状態はチェックして // いないので、ここで自発的に行う。 if (fd_loaded[unit] != new_loaded) { fd_loaded[unit] = new_loaded; - - LayoutIndicators(); Refresh(); } }