--- nono/wx/wxmonitor.cpp 2026/04/29 17:04:56 1.1.1.5 +++ nono/wx/wxmonitor.cpp 2026/04/29 17:05:12 1.1.1.7 @@ -4,8 +4,72 @@ // 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); +} + // // モニターウィンドウ @@ -16,44 +80,130 @@ WXMonitorWindow::WXMonitorWindow(wxWindo Monitor& monitor_) : inherited(parent, wxID_ANY, name) { - // top - // | +----------------------------+ - // v | 上余白 | - // |+------+------------+------+| - // ||左余白| TextScreen |右余白|| - // |+------+------------+------+| - // | 下余白 | - // +----------------------------+ - - wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL); - - // 上余白 - topsizer->Add(new WXPaddingPanel(this), 0, wxEXPAND); - - // 中段(横sizer) - wxBoxSizer *hbox = new wxBoxSizer(wxHORIZONTAL); - topsizer->Add(hbox, 0, wxEXPAND); - - // 左余白 - hbox->Add(new WXPaddingPanel(this), 0, wxEXPAND); - - // テキストスクリーン - screen = new WXTextScreen(this, monitor_); - hbox->Add(screen, 0, wxEXPAND); + // モニタパネル + monpanel = new WXMonitorPanel(this, monitor_); + DoSize(); +} + +// デストラクタ +WXMonitorWindow::~WXMonitorWindow() +{ +} + - // 右余白 - hbox->Add(new WXPaddingPanel(this), 0, wxEXPAND); +// +// 縦スクロールバー付きモニタウィンドウ +// - // 下余白 - topsizer->Add(new WXPaddingPanel(this), 0, wxEXPAND); +// イベントテーブル +wxBEGIN_EVENT_TABLE(WXScrollMonitorWindow, inherited) + EVT_SIZE(WXScrollMonitorWindow::OnSize) +wxEND_EVENT_TABLE() + +// コンストラクタ +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); - // 大きさをそれに固定 - Fit(); + // ウィンドウサイズを確定させる + DoSize(); + + // スクロールのために (パネル領域での) 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 +WXScrollMonitorWindow::OnScroll(wxScrollEvent& event) +{ + DoScroll(event.GetPosition()); +} + +// スクロール処理 (OnScroll() と OnMouseWheel() から呼ばれる) +void +WXScrollMonitorWindow::DoScroll(int pos) { + // userdata が表示開始位置になっている + monpanel->SetUserData(pos); + monpanel->DoRefresh(); }