--- nono/wx/wxmainview.cpp 2026/04/29 17:05:04 1.1.1.10 +++ nono/wx/wxmainview.cpp 2026/04/29 17:05:08 1.1.1.11 @@ -4,12 +4,17 @@ // Licensed under nono-license.txt // +// +// メイン画面パネル +// + #include "wxmainview.h" +#include "wxuimessage.h" +#include "bitmap.h" #include "config.h" +#include "event.h" #include "keyboard.h" #include "renderer.h" -#include "scheduler.h" -#include #include //#define KEYDEBUG 1 @@ -43,8 +48,6 @@ #define DONT_USE_REFRESH 1 #endif -static void wxmainview_refresh(); - WXMainView *gMainView; wxBEGIN_EVENT_TABLE(WXMainView, inherited) @@ -53,7 +56,6 @@ wxBEGIN_EVENT_TABLE(WXMainView, inherite EVT_KEY_UP(WXMainView::OnKeyUp) EVT_CHAR(WXMainView::OnChar) EVT_MOUSE_EVENTS(WXMainView::OnMouse) - EVT_TIMER(wxID_ANY, WXMainView::OnTimer) wxEND_EVENT_TABLE() WXMainView::WXMainView(wxWindow *parent) @@ -63,19 +65,17 @@ WXMainView::WXMainView(wxWindow *parent) rendwidth = gRenderer->GetWidth(); rendheight = gRenderer->GetHeight(); - // レンダラバッファは常に仮想画面サイズ - int buflen = rendwidth * rendheight * 3; - ImageBuf.reset(new uint8_t[buflen]); - memset(&ImageBuf[0], 0x70, buflen); - // レンダラに通知 - gRenderer->SetBuf(ImageBuf.get(), wxmainview_refresh); + gRenderer->Enable(); + + // VM からの通知を受け取る + WXUIMessage::Connect(UIMessage::RENDER, this, + wxCommandEventHandler(WXMainView::OnRender)); // 実画面 (ウィンドウの大きさ) DoResize(screen_scale); - // 描画を律速するためのタイマー - timer.SetOwner(this); - timer.Start(33); + // 更新間隔 + gRenderer->SetRefreshInterval(33_msec); // 最初に一度描画 Refresh(); @@ -87,6 +87,8 @@ WXMainView::~WXMainView() if (HasCapture()) { ReleaseMouse(); } + WXUIMessage::Disconnect(UIMessage::RENDER, + wxCommandEventHandler(WXMainView::OnRender)); } // (設定反映などの) 初期化 @@ -109,17 +111,18 @@ WXMainView::Init() return true; } -// リフレッシュ要求コールバック。 -// VM から呼ばれるので一旦グローバル関数を経由する。 +// 終了用に描画を停止する void -wxmainview_refresh(void) +WXMainView::Close() { - gMainView->DoRefresh(); + // これで OnPaint() が何もせず帰るようになる。 + viewwidth = 0; + viewheight = 0; } -// リフレッシュ要求コールバック。こっちが実体。 +// リフレッシュ要求イベント void -WXMainView::DoRefresh() +WXMainView::OnRender(wxCommandEvent& event) { #if defined(DONT_USE_REFRESH) // Refresh{,Rect}() が使えないので、再描画範囲は常に全体とする @@ -128,65 +131,36 @@ WXMainView::DoRefresh() // XXX のはずだが、今の所全体 RefreshRect(wxRect(0, 0, viewwidth, viewheight), false); #endif - - // ここは VM Renderer が画面を更新した時に呼ばれるので、本来なら - // ここで単に Refresh() を呼んで再描画を指示すればいいのだが、 - // VM 高速モードになると、VM Renderer が高速で回ってここも高速で - // 呼ばれてしまい、その結果 Refresh() を発行しすぎて Mac では - // システムイベントが拾えなくなってしまう。 - // それを避けるため、ここではフラグを立てるだけにしておいて、 - // こちらで管理している実時間タイマーで Refresh() を律速する。 - paint_request = true; -} - -// タイマーイベント -void -WXMainView::OnTimer(wxTimerEvent& event) -{ - bool req = paint_request.exchange(false); - if (req) { - // 実際に再描画する - Refresh(); - } + // 実際に再描画する + Refresh(); + // TODO: ビデオモニタにも通知する } // 描画イベント void WXMainView::OnPaint(wxPaintEvent& event) { - if (viewwidth == 0 || viewheight == 0) + if (__predict_false(viewwidth == 0 || viewheight == 0)) { return; + } + + const BitmapRGB& bitmap0 = gRenderer->GetBitmap(); + BitmapRGB bitmap1; + uint8 *p = const_cast(bitmap0.GetBuf()); - wxImage image(rendwidth, rendheight, ImageBuf.get(), true); if (viewwidth != rendwidth || viewheight != rendheight) { - // wxIMAGE_QUALITY_NORMAL だと速いが、ここは品質優先。 -#if _BYTE_ORDER == _BIG_ENDIAN - // XXX ..のはずだったが wxWidget 3.0.4 の QUALITY_HIGH は - // BigEndian だとバグってるようだ。QUALITY_NORMAL のほうは大丈夫。 - auto quality = wxIMAGE_QUALITY_NORMAL; -#else - auto quality = wxIMAGE_QUALITY_HIGH; -#endif - image.Rescale(viewwidth, viewheight, quality); + bitmap1.Create(viewwidth, viewheight); + Rect rect(0, 0, viewwidth, viewheight); + bitmap1.StretchDraw(rect, bitmap0); + p = bitmap1.GetBuf(); } - wxBitmap bitmap(image); - wxMemoryDC memDC; - memDC.SelectObject(bitmap); - - wxPaintDC dc(this); - wxRegion region(0, 0, viewwidth, viewheight); - wxRegionIterator ri(region); - for (; ri; ri++) { - int dx, dy, dw, dh; - dx = ri.GetX(); - dy = ri.GetY(); - dw = ri.GetWidth(); - dh = ri.GetHeight(); - int sx = dx; - int sy = dy; - dc.Blit(dx, dy, dw, dh, &memDC, sx, sy, wxCOPY); - } + wxImage image(viewwidth, viewheight, p, true); + wxBitmap bmp(image); + + // 実画面 DC にコピー + wxPaintDC dstDC(this); + dstDC.DrawBitmap(bmp, 0, 0); } // リサイズ (UI スレッドから呼ぶこと) @@ -469,6 +443,9 @@ WXMainView::OnKeyUp(wxKeyEvent& event) void WXMainView::OnChar(wxKeyEvent& event) { + // メニューのアクセラレータのために必要 + event.Skip(); + if (!is_charinput) { return; } @@ -833,7 +810,7 @@ WXMainView::keycode_table[0x190] = { 0, // 310 WXK_PAUSE 0, // 311 WXK_CAPITAL 0, // 312 WXK_END - 0, // 313 WXK_HOME + KC_HOME, // 313 WXK_HOME KC_left, // 314 WXK_LEFT KC_up, // 315 WXK_UP KC_right, // 316 WXK_RIGHT