--- nono/wx/wxmonitor.cpp 2026/04/29 17:04:37 1.1.1.2 +++ nono/wx/wxmonitor.cpp 2026/04/29 17:05:12 1.1.1.7 @@ -4,68 +4,206 @@ // Licensed under nono-license.txt // +// +// モニター +// + #include "wxmonitor.h" -#include "wxtextscreen.h" +#include "wxmainframe.h" + +// +// モニターパネル +// + +// イベントテーブル +wxBEGIN_EVENT_TABLE(WXMonitorPanel, inherited) + EVT_TIMER(wxID_ANY, WXMonitorPanel::OnTimer) +wxEND_EVENT_TABLE() + +// コンストラクタ +WXMonitorPanel::WXMonitorPanel(wxWindow *parent, Monitor& monitor_) + : inherited(parent, monitor_.GetSize()) + , monitor(monitor_) +{ + timer.SetOwner(this); + + // 現在の設定値を適用 + SetRate(gMainFrame->GetMonitorRate()); + + // 最初に一回描画を起こす + wxTimerEvent dummy(timer); + AddPendingEvent(dummy); +} + +// デストラクタ +WXMonitorPanel::~WXMonitorPanel() +{ +} + +// タイマーイベント +void +WXMonitorPanel::OnTimer(wxTimerEvent& event) +{ + DoRefresh(); +} + +// 画面を更新して再描画する。 +// +// 通常はタイマーイベントにより更新間隔ごとに呼ばれるが、 +// ユーザ操作により画面の更新が必要ならその都度直接これを呼ぶ。 +void +WXMonitorPanel::DoRefresh() +{ + // モニタースクリーンを更新して + MONITOR_UPDATE(monitor, screen); + + // 必要なら再描画 + if (screen.GetBuf() != prevbuf) { + Refresh(); + } +} + +// 画面更新頻度を Hz で設定する。 +void +WXMonitorPanel::SetRate(int hz) +{ + timer.Start(1000 / hz); +} + // // モニターウィンドウ // +// コンストラクタ +WXMonitorWindow::WXMonitorWindow(wxWindow *parent, const wxString& name, + Monitor& monitor_) + : inherited(parent, wxID_ANY, name) +{ + // モニタパネル + monpanel = new WXMonitorPanel(this, monitor_); + DoSize(); +} + +// デストラクタ +WXMonitorWindow::~WXMonitorWindow() +{ +} + + +// +// 縦スクロールバー付きモニタウィンドウ +// + // イベントテーブル -wxBEGIN_EVENT_TABLE(WXMonitorWindow, inherited) - EVT_TIMER(wxID_ANY, WXMonitorWindow::OnTimer) +wxBEGIN_EVENT_TABLE(WXScrollMonitorWindow, inherited) + EVT_SIZE(WXScrollMonitorWindow::OnSize) wxEND_EVENT_TABLE() // コンストラクタ -WXMonitorWindow::WXMonitorWindow(wxWindow *parent, wxWindowID id, - const wxString& name, Object *obj) - : inherited(parent, id, name) -{ - object = obj; - assert(object); - - wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL); - - // テキストスクリーン - TextScreen& monitor = object->monitor; - int col = monitor.GetCol(); - int row = monitor.GetRow(); - const uint16 *textbuf = monitor.GetBuf(); - screen = new WXTextScreen(this, col, row, textbuf); - topsizer->Add(screen, BorderFlags); +WXScrollMonitorWindow::WXScrollMonitorWindow(wxWindow *parent, + const wxString& name, Monitor& monitor_) + : inherited(parent, wxID_ANY, name, DEFAULT_STYLE | wxRESIZE_BORDER) +{ + // → + // +--------------+---------+ + // | MonitorPanel | VScroll | + // +--------------+---------+ + + wxBoxSizer *topsizer = new wxBoxSizer(wxHORIZONTAL); + + // モニタパネル + monpanel = new WXMonitorPanel(this, monitor_); + topsizer->Add(monpanel, 1, wxEXPAND); + + // スクロールバー + vscroll = new WXScrollBar(this, wxID_ANY, wxSB_VERTICAL); + topsizer->Add(vscroll, 0, wxEXPAND); SetSizer(topsizer); - // 大きさをそれに固定 - Layout(); - Fit(); + // ウィンドウサイズを確定させる + DoSize(); - // 更新タイマーは適当な短さにしておく - timer.SetOwner(this); - timer.Start(10); + // スクロールのために (パネル領域での) MouseWheel イベントもここで + // 受け取りたい。スクロールバー上のマウスホイール操作はスクロールバーが + // 処理しているので問題ないが、パネル領域でのマウスホイール操作はここ + // (wxFrame)ではなくパネルに対して飛んでくる。 + // ここで一緒に処理したほうが楽なので、こちらに回す。 + monpanel->Connect(wxEVT_MOUSEWHEEL, + wxMouseEventHandler(WXScrollMonitorWindow::OnMouseWheel), NULL, this); + + // スクロールバーからの位置変更通知 + vscroll->Connect(NONO_EVT_SCROLL, + wxScrollEventHandler(WXScrollMonitorWindow::OnScroll), NULL, this); } // デストラクタ -WXMonitorWindow::~WXMonitorWindow() +WXScrollMonitorWindow::~WXScrollMonitorWindow() { } -// タイマーイベント +bool +WXScrollMonitorWindow::Layout() +{ + // 縦リサイズ可能レイアウト + return LayoutTextVResize(monpanel); +} + +// サイズ変更イベント +void +WXScrollMonitorWindow::OnSize(wxSizeEvent& event) +{ + inherited::OnSize(event); + + // 今の所ヘッダが常に1行ある + static int HEADLINES = 1; + + // スクロールバーを再設定 + int pos = (int)monpanel->GetUserData(); + int thumbsize = monpanel->GetRow() - HEADLINES; + int range = monpanel->GetMonitor().GetMaxHeight() - HEADLINES; + int pagesize = thumbsize - 1; + if (pos > range - thumbsize) { + pos = range - thumbsize; + DoScroll(pos); + } + vscroll->SetScrollParam(pos, thumbsize, range, pagesize); +} + +// マウスホイールイベント (WXTextScreen 上で起きたやつをこっちに回してある) +void +WXScrollMonitorWindow::OnMouseWheel(wxMouseEvent& event) +{ + // GetWheelRotation() は上(奥)向きに回すと +120、下(手前)に回すと -120。 + // どこの決まりか知らんけど、スクロールバーのほうはホイール1段階で3行 + // スクロールするのでそれに合わせる。 + int pos = (int)monpanel->GetUserData(); + pos = pos - event.GetWheelRotation() / 40; + + int maxpos = vscroll->GetRange() - vscroll->GetThumbSize(); + if (pos < 0) + pos = 0; + if (pos > maxpos) + pos = maxpos; + + DoScroll(pos); + // スクロールバーの位置を追従 + vscroll->SetThumbPosition(pos); +} + +// スクロールバーからの通知イベント void -WXMonitorWindow::OnTimer(wxTimerEvent& event) +WXScrollMonitorWindow::OnScroll(wxScrollEvent& event) { - // モニタースクリーンを更新して再描画。 - bool avail = object->MonitorUpdate(); - assert(avail); - screen->Refresh(); + DoScroll(event.GetPosition()); } -// フォントサイズ変更 +// スクロール処理 (OnScroll() と OnMouseWheel() から呼ばれる) void -WXMonitorWindow::SetFontSize(fontsize_t fontsize) +WXScrollMonitorWindow::DoScroll(int pos) { - screen->SetFontSize(fontsize); - // 大きさを変更 - Layout(); - Fit(); + // userdata が表示開始位置になっている + monpanel->SetUserData(pos); + monpanel->DoRefresh(); }