--- nono/wx/wxtextscreen.cpp 2026/04/29 17:04:28 1.1 +++ nono/wx/wxtextscreen.cpp 2026/04/29 17:04:43 1.1.1.4 @@ -1,93 +1,80 @@ // // nono -// Copyright (C) 2018 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt // -#include "wxheader.h" #include "wxtextscreen.h" +#include "wxmainframe.h" #include "bitrev.h" #include "cgrom.h" // -// テキストスクリーン風コントロール +// テキストスクリーンを表示するパネル // // イベントテーブル wxBEGIN_EVENT_TABLE(WXTextScreen, inherited) EVT_PAINT(WXTextScreen::OnPaint) EVT_SIZE(WXTextScreen::OnSize) + EVT_TIMER(wxID_ANY, WXTextScreen::OnTimer) wxEND_EVENT_TABLE() // コンストラクタ -WXTextScreen::WXTextScreen(wxWindow *parent, int arg_col, int arg_row, - const uint16 *arg_textbuf) +WXTextScreen::WXTextScreen(wxWindow *parent, IMonitor& monitor_) : inherited(parent) + , monitor(monitor_) { - col = arg_col; - row = arg_row; - textbuf = arg_textbuf; + // モニタサイズから初期サイズを決定 + nnSize ms = monitor.GetMonitorSize(); + wxSize size = wxSize(ms.width * font_width, ms.height * font_height); + SetClientSize(size); + SetMinSize(size); + + timer.SetOwner(this); + + // 現在の設定値を適用 + SetRate(gMainFrame->GetMonitorRate()); - SetTextSize(col, row); + // 最初に一回描画を起こす + wxTimerEvent dummy; + AddPendingEvent(dummy); } // デストラクタ WXTextScreen::~WXTextScreen() { - if (bitmap) { - delete bitmap; - } - if (image) { - delete image; - } - if (bmpbuf) { - delete bmpbuf; - } - if (prevbuf) { - delete[] prevbuf; - } + bitmap.reset(); + image.reset(); + bmpbuf.reset(); + prevbuf.reset(); } -// このパネルの(テキストでの)大きさを設定する。 +// 画面更新頻度を Hz で設定する。 void -WXTextScreen::SetTextSize(int acol, int arow) +WXTextScreen::SetRate(int hz) { - col = acol; - row = arow; - int width = col * font_width; - int height = row * font_height; - - if (wxSize(width, height) == wxSize(view_width, view_height)) { - return; - } - - // サイズ変更イベント側でやるか - if (prevbuf) { - delete[] prevbuf; - prevbuf = NULL; - } - prevbuf = new uint16 [col * row]; - memset(prevbuf, 0xff, col * row * sizeof(*prevbuf)); - - SetClientSize(width, height); - SetMinSize(wxSize(width, height)); + timer.Start(1000 / hz); } // フォントサイズ変更 (外部インタフェース) void -WXTextScreen::SetFontSize(fontsize_t new_fontsize) +WXTextScreen::SetFontSize(FontId new_fontid) { // 同じなら何もしない - if (fontsize == new_fontsize) { + if (fontid == new_fontid) { return; } // フォントを更新 - UpdateFont(new_fontsize); + UpdateFont(new_fontid); // 再描画を強制する。 // テキストの桁数行数は変わってないので再確保はしなくていい。 - assert(prevbuf); - memset(prevbuf, 0xff, col * row * sizeof(*prevbuf)); + int col = ts.GetCol(); + int row = ts.GetRow(); + assert((bool)prevbuf); + memset(&prevbuf[0], 0xff, col * row * sizeof(prevbuf[0])); // コントロールの大きさを変更 wxSize size = wxSize(col * font_width, row * font_height); @@ -101,46 +88,68 @@ WXTextScreen::OnSize(wxSizeEvent& event) { // Mac ではウィンドウ作成時に 0 以下の値が来ることがある // GTK では 1 で来ることがある - wxSize size = event.GetSize(); + const wxSize& size = event.GetSize(); if (size.x <= 1 || size.y <= 1) { return; } - view_width = size.x; - view_height = size.y; - - // ビットマップを持っていれば一旦解放 - if (bitmap) { - delete bitmap; - bitmap = NULL; - } - if (image) { - delete image; - image = NULL; - } - if (bmpbuf) { - delete bmpbuf; - bmpbuf = NULL; + // テキストサイズが変わった時だけテキストバッファを再構成。 + // (フォントサイズを変えると桁数×行数が変わらず画面サイズが変わる + // ということは起きることに注意) + int col = size.x / font_width; + int row = size.y / font_height; + if (col != ts.GetCol() || row != ts.GetRow()) { + ts.Init(col, row); + prevbuf.reset(new uint16 [col * row]); + memset(&prevbuf[0], 0xff, col * row * sizeof(prevbuf[0])); + } + + // ビットマップサイズが変わった時だけビットマップバッファを再構成。 + if (col * font_width != view_width || row * font_height != view_height) { + // ビットマップを持っていれば (この順序で) 一旦解放 + bitmap.reset(); + image.reset(); + bmpbuf.reset(); + + // ビットマップ作成 + view_width = col * font_width; + view_height = row * font_height; + bmpbuf.reset(new uint8 [view_width * view_height * 3]); + // 正しく描かれなかった時に分かりやすいよう初期値は濃いグレーにしておく + memset(&bmpbuf[0], 0x70, view_width * view_height * 3); + image.reset(new wxImage(view_width, view_height, bmpbuf.get(), true)); + bitmap.reset(new wxBitmap(*image)); } +} - // ビットマップ作成 - // 正しく描かれなかった時に分かりやすいよう初期値は濃いグレーにしておく - bmpbuf = new uint8 [view_width * view_height * 3]; - memset(bmpbuf, 0x70, view_width * view_height * 3); - image = new wxImage(view_width, view_height, bmpbuf, true); - bitmap = new wxBitmap(*image); +// タイマーイベント +void +WXTextScreen::OnTimer(wxTimerEvent& event) +{ + // モニタースクリーンを更新して再描画。 + monitor.MonitorUpdate(ts); + RefreshIfUpdated(); +} + +// 必要なら画面を更新して再描画する +void +WXTextScreen::RefreshIfUpdated() +{ + int len = ts.GetCol() * ts.GetRow() * sizeof(prevbuf[0]); + if (memcmp(ts.GetBuf(), &prevbuf[0], len) != 0) { + Refresh(); + } } // 描画イベント (UI スレッドから呼ばれる) void WXTextScreen::OnPaint(wxPaintEvent& event) { - // 更新があればメモリ DC に描画 + // メモリ DC に描画 wxMemoryDC memDC; memDC.SelectObject(*bitmap); - if (memcmp(textbuf, prevbuf, col * row * sizeof(*prevbuf)) != 0) { - Draw(memDC); - } + // 基本的には RefreshIfUpdated() により更新があった時だけ呼ばれる + Draw(memDC); // 実画面 DC にコピー wxPaintDC dstDC(this); @@ -151,8 +160,10 @@ WXTextScreen::OnPaint(wxPaintEvent& even void WXTextScreen::Draw(wxDC& dc) { - const uint16 *text = textbuf; - uint16 *prev = prevbuf; + const uint16 *text = ts.GetBuf(); + uint16 *prev = &prevbuf[0]; + int col = ts.GetCol(); + int row = ts.GetRow(); int px = 0; int py = 0; for (int y = 0; y < row; y++, py += font_height) { @@ -164,6 +175,10 @@ WXTextScreen::Draw(wxDC& dc) if (__predict_true(chr < 128)) { // ASCII if (*prev != data) { + if (*prev >= 128 && x != col - 1) { + // prev がマルチバイトだったときは 2byte 目も消す + prev[1] = 0; + } DrawChar1(dc, px, py, chr, attr); *prev = data; } @@ -174,7 +189,7 @@ WXTextScreen::Draw(wxDC& dc) } else { // マルチバイト文字は Shift_JIS として処理する uint code = (chr << 8) | (text[1] & 0xff); - if (*(uint32 *)prev != *(uint32 *)text) { + if (prev[0] != data || prev[1] != text[1]) { DrawChar2(dc, px, py, code, attr); } *prev++ = *text++;