--- nono/wx/wxtextscreen.cpp 2026/04/29 17:04:43 1.1.1.4 +++ nono/wx/wxtextscreen.cpp 2026/04/29 17:04:53 1.1.1.5 @@ -5,9 +5,11 @@ // #include "wxtextscreen.h" +#include "wxcolor.h" #include "wxmainframe.h" #include "bitrev.h" #include "cgrom.h" +#include "sjis.h" // // テキストスクリーンを表示するパネル @@ -27,9 +29,11 @@ WXTextScreen::WXTextScreen(wxWindow *par { // モニタサイズから初期サイズを決定 nnSize ms = monitor.GetMonitorSize(); + Init(ms.width, ms.height); + wxSize size = wxSize(ms.width * font_width, ms.height * font_height); SetClientSize(size); - SetMinSize(size); + SetMinClientSize(size); timer.SetOwner(this); @@ -44,10 +48,15 @@ WXTextScreen::WXTextScreen(wxWindow *par // デストラクタ WXTextScreen::~WXTextScreen() { - bitmap.reset(); - image.reset(); - bmpbuf.reset(); - prevbuf.reset(); +} + +// (再)初期化 +void +WXTextScreen::Init(int col, int row) +{ + ts.Init(col, row); + prevbuf.resize(col * row); + std::fill(prevbuf.begin(), prevbuf.end(), 0xffff); } // 画面更新頻度を Hz で設定する。 @@ -71,15 +80,12 @@ WXTextScreen::SetFontSize(FontId new_fon // 再描画を強制する。 // テキストの桁数行数は変わってないので再確保はしなくていい。 - int col = ts.GetCol(); - int row = ts.GetRow(); - assert((bool)prevbuf); - memset(&prevbuf[0], 0xff, col * row * sizeof(prevbuf[0])); + std::fill(prevbuf.begin(), prevbuf.end(), 0xffff); // コントロールの大きさを変更 - wxSize size = wxSize(col * font_width, row * font_height); + wxSize size = wxSize(ts.GetCol() * font_width, ts.GetRow() * font_height); SetClientSize(size); - SetMinSize(size); + SetMinClientSize(size); } // サイズ変更イベント @@ -99,26 +105,15 @@ WXTextScreen::OnSize(wxSizeEvent& event) 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])); + Init(col, row); } // ビットマップサイズが変わった時だけビットマップバッファを再構成。 - if (col * font_width != view_width || row * font_height != view_height) { - // ビットマップを持っていれば (この順序で) 一旦解放 - bitmap.reset(); - image.reset(); - bmpbuf.reset(); - + wxSize bmpsize = bitmap.GetSize(); + wxSize newsize = wxSize(col * font_width, row * font_height); + if (bmpsize != newsize) { // ビットマップ作成 - 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)); + bitmap.Create(newsize); } } @@ -135,8 +130,7 @@ WXTextScreen::OnTimer(wxTimerEvent& even void WXTextScreen::RefreshIfUpdated() { - int len = ts.GetCol() * ts.GetRow() * sizeof(prevbuf[0]); - if (memcmp(ts.GetBuf(), &prevbuf[0], len) != 0) { + if (ts.GetBuf() != prevbuf) { Refresh(); } } @@ -147,53 +141,82 @@ WXTextScreen::OnPaint(wxPaintEvent& even { // メモリ DC に描画 wxMemoryDC memDC; - memDC.SelectObject(*bitmap); + memDC.SelectObject(bitmap); // 基本的には RefreshIfUpdated() により更新があった時だけ呼ばれる Draw(memDC); // 実画面 DC にコピー wxPaintDC dstDC(this); - dstDC.Blit(0, 0, view_width, view_height, &memDC, 0, 0); + wxSize size = bitmap.GetSize(); + dstDC.Blit(0, 0, size.x, size.y, &memDC, 0, 0); } // テキストバッファの内容をパネルのバックグラウンドバッファに描画する。 void WXTextScreen::Draw(wxDC& dc) { - const uint16 *text = ts.GetBuf(); - uint16 *prev = &prevbuf[0]; + auto text = ts.GetBuf().begin(); + auto prev = prevbuf.begin(); + int col = ts.GetCol(); int row = ts.GetRow(); int px = 0; int py = 0; + uint prevattr = (uint)-1; + for (int y = 0; y < row; y++, py += font_height) { px = 0; for (int x = 0; x < col; ) { uint16 data = *text; uint attr = (data & 0xff00); uint chr = (data & 0xff); - if (__predict_true(chr < 128)) { - // ASCII + + // 属性(色)を変更 + if (__predict_false(attr != prevattr)) { + switch (attr) { + case TA::On: + SetTextColor(BGPANEL, *wxBLACK); + break; + case TA::Disable: + SetTextColor(UD_GREY, BGPANEL); + break; + default: + ResetTextColor(); + break; + } + prevattr = attr; + } + + if (__predict_true(SJIS::IsHankaku(chr))) { + // 半角文字 if (*prev != data) { - if (*prev >= 128 && x != col - 1) { - // prev がマルチバイトだったときは 2byte 目も消す + DrawChar1(dc, px, py, chr, attr); + if (SJIS::IsZenkaku(*prev) && x < col - 1) { + // 変更前が全角文字だったら 2 バイト目も消す prev[1] = 0; } - DrawChar1(dc, px, py, chr, attr); *prev = data; } - prev++; - text++; - x++; - px += font_width; + prev += 1; + text += 1; + x += 1; + px += font_width * 1; } else { - // マルチバイト文字は Shift_JIS として処理する - uint code = (chr << 8) | (text[1] & 0xff); - if (prev[0] != data || prev[1] != text[1]) { + // 全角文字 + // XXX: 最右カラムだったら? + if (*prev != data || prev[1] != text[1]) { + uint code = (chr << 8) | (text[1] & 0xff); DrawChar2(dc, px, py, code, attr); + if (SJIS::IsASCII(*prev) && SJIS::IsZenkaku(prev[1]) + && x < col - 2) { + // 変更前が 'Aあ' だったら'あ'の2バイト目も消す + prev[2] = 0; + } + prev[0] = data; + prev[1] = text[1]; } - *prev++ = *text++; - *prev++ = *text++; + prev += 2; + text += 2; x += 2; px += font_width * 2; }