--- nono/wx/wxtextpanel.cpp 2026/04/29 17:04:37 1.1.1.3 +++ nono/wx/wxtextpanel.cpp 2026/04/29 17:05:57 1.1.1.12 @@ -4,392 +4,118 @@ // Licensed under nono-license.txt // -#include "wxtextpanel.h" -#include "wxcolor.h" -#include "bitrev.h" -#include "cgrom.h" -#include "kaname12.h" - -// wxOSX(-3.0.2) の wxLIGHT_GREY は値が(色も透明度も)正しくない。 -// wxGTK の wxLIGHT_GREY は 0xffd3d3d3 だけどこれを Mac で見ると -// (Mac の統一感としては) 暗く見えるので色コード自体を変える。 -#if defined(__WXOSX__) -#define LIGHT_GREY wxColour(0xffe0e0e0) -#else -#define LIGHT_GREY *wxLIGHT_GREY -#endif - // -// テキストフォントを管理するクラス +// テキストフォントを描画するパネル // -static struct fontinfo { - int width; - int height; -} fontinfo[] = { - // 順序はヘッダの FONT_* 識別子の順と揃えること - { 6, 12 }, - { 8, 16 }, -}; -static_assert(countof(fontinfo) == FONT_MAX, ""); +#include "wxtextpanel.h" +#include "fontmanager.h" +#include "sjis.h" // コンストラクタ -WXTextPanel::WXTextPanel(wxWindow *parent) - : inherited(parent, wxID_ANY) +WXTextPanel::WXTextPanel(wxWindow *parent, wxWindowID id, + const wxPoint& position, const wxSize& size, long style) + : inherited(parent, id, position, size, style) { - UpdateFont(global_fontsize); - // デフォルト色 - SetTextColor(*wxBLACK, LIGHT_GREY, wxColour(0x50, 0x50, 0x50)); + ResetTextColor(); } // デストラクタ WXTextPanel::~WXTextPanel() { - FreeFont(fontsize); } -// フォント関連の内部情報をよしなに更新する void -WXTextPanel::UpdateFont(fontsize_t new_fontsize) +WXTextPanel::FontChanged() { - assert(fontsize != new_fontsize); - - // フォントデータを更新 - FreeFont(fontsize); - AllocFont(new_fontsize); - - // 内部変数を更新 - fontsize = new_fontsize; - font_width = fontinfo[fontsize].width; - font_height = fontinfo[fontsize].height; - ascii_glyph = ascii_glyph_table[fontsize]; - bold_glyph = bold_glyph_table[fontsize]; + font_width = gFontManager->GetFontWidth(); + font_height = gFontManager->GetFontHeight(); } -// 必要ならフォントを用意する -/*static*/ void -WXTextPanel::AllocFont(fontsize_t fontsize) +// テキスト色をデフォルトに設定する(戻す) +void +WXTextPanel::ResetTextColor() { - const uint8 *base; - - std::unique_lock lock(global_font_mutex); - if (font_refcnt[fontsize]++ != 0) { - return; - } - - // 6x12, 8x16 半角は X68030 CGROM にあるのでそれを使う - switch (fontsize) { - case FONT_6x12: - base = BuiltinCGROM::Get6x12(); - break; - case FONT_8x16: - base = BuiltinCGROM::Get8x16(); - break; - default: - assertmsg(0, "fontsize=%d", fontsize); - } - - // フォントの行ストライド[byte] - int font_width = fontinfo[fontsize].width; - int font_height = fontinfo[fontsize].height; - int font_stride = (font_width + 7) / 8; - int bytes = font_stride * font_height; - std::vector buf(bytes); - - wxBitmap **ascii_glyph = ascii_glyph_table[fontsize]; - wxBitmap **bold_glyph = bold_glyph_table[fontsize]; - // ASCII というか半角というかは通常 0x7f までだが - // X680x0 の CGROM の 0x80, 0x81, 0x82 には '\\', '~', '|' が - // 収納されているのでここまで含めてデータを作っておく。 - for (int ch = 0; ch < countof(ascii_glyph_table[0]); ch++) { - const uint8 *ptr = base + ch * bytes; - - // wxBitmap は XBM 形式で 1bpp ビットマップを受け取る。 - // XBM は MSB が右なので、ビット左右を反転する - for (int i = 0; i < bytes; i++) { - uint8 src = ptr[i]; - buf[i] = bitrev(src); - } - // その XBM データから1文字分のビットマップオブジェクトを作成 - ascii_glyph[ch] = new wxBitmap(&buf[0], font_width, font_height, 1); - - // 続いてボールドに加工 - for (int i = 0; i < bytes; i++) { - // XBM 形式は MSB が右なので左シフトすると一般的なボールド。 - buf[i] |= ((uint8)buf[i] << 1); - } - bold_glyph[ch] = new wxBitmap(&buf[0], font_width, font_height, 1); - } + SetTextColor(UD_BLACK, BGPANEL); } -// 最後の一人ならフォントを解放する -/*static*/ void -WXTextPanel::FreeFont(fontsize_t fontsize) +// テキスト色を指定する +void +WXTextPanel::SetTextColor(Color fg, Color bg) { - std::unique_lock lock(global_font_mutex); - - if (fontsize < 0 || fontsize >= FONT_MAX) { - return; - } - if (--font_refcnt[fontsize] != 0) { - return; - } - - wxBitmap **ascii_glyph = ascii_glyph_table[fontsize]; - wxBitmap **bold_glyph = bold_glyph_table[fontsize]; - for (int i = 0; i < countof(ascii_glyph_table[0]); i++) { - if (ascii_glyph[i]) { - delete ascii_glyph[i]; - ascii_glyph[i] = NULL; - } - if (bold_glyph[i]) { - delete bold_glyph[i]; - bold_glyph[i] = NULL; - } - } + palette[FG] = fg; + palette[BG] = bg; } -// テキスト色を指定する +// (px, py) を左上とする座標から Shift_JIS 文字列を、前景色 c、属性 attr で +// 描画する。 +// ただし attr のうちここで参照するのは EM (ボールド) かそうでないかのみ。 +// フォントサイズは現行のフォント。 +// キャンバスをはみ出さないこと。 void -WXTextPanel::SetTextColor(const wxColour& fg, const wxColour& bg, - const wxColour& dc) +WXTextPanel::DrawStringSJIS(Color c, int px, int py, const char *sjis, + uint attr) { - text_fgcolor = fg; - text_bgcolor = bg; - text_disable_color = dc; + Color backup = palette[FG]; + + palette[FG] = c; + DrawStringSJIS(px, py, sjis, attr); + palette[FG] = backup; } // (px, py) を左上とする座標から Shift_JIS 文字列を属性 attr で描画する。 -// 文字列中で属性を変えることはできない。 -// キャンバスをはみ出すかどうかについてはこちらでは関知しない。 +// ただし attr のうちここで参照するのは EM (ボールド) かそうでないかのみ。 +// 描画色、背景色は事前に SetTextColor() で設定したもの。 // フォントサイズは現行のフォント。 +// キャンバスをはみ出さないこと。 void -WXTextPanel::DrawStringSJIS(wxDC& dc, int px, int py, const char *sjis, - uint attr) +WXTextPanel::DrawStringSJIS(int px, int py, const char *sjis, uint attr) { const uint8 *s; for (s = (const uint8 *)sjis; *s; ) { - if (__predict_true(*s < 0x80)) { - // ASCII - DrawChar1(dc, px, py, *s++, attr); - px += font_width; - } else if (0xa0 <= *s && *s < 0xe0) { - // 半角カナ - DrawCharKana(dc, px, py, *s++, attr); + if (__predict_true(SJIS::IsHankaku(*s))) { + // 半角 + DrawChar1(px, py, *s++, attr); px += font_width; } else { // 全角 - int code; + uint code; code = (*s++ << 8); code |= *s++; - DrawChar2(dc, px, py, code, attr); + DrawChar2(px, py, code, attr); px += font_width * 2; } } } -// (px, py) を左上とする座標からASCII文字 code を属性 attr で描画する。 -// code は 0x80 未満。 +// (px, py) を左上とする座標から半角文字 code を属性 attr で描画する。 +// code は ASCII または半角カナ。attr のうち反応するのは Bold のみ。 // フォントサイズは現行のフォント。 void -WXTextPanel::DrawChar1(wxDC& dc, int px, int py, uint code, uint attr) +WXTextPanel::DrawChar1(int px, int py, uint code, uint attr) { - wxBitmap **glyph; + assertmsg(code < 0x100, "code=0x%x", code); - assertmsg(code < 0x80, "code=0x%x", code); - - // ボールドかどうかでテーブルが別 - if ((attr & TA::Em)) { - glyph = bold_glyph; - } else { - glyph = ascii_glyph; + const uint8 *glyph = gFontManager->AsciiGlyph(code); + BitmapI1 src(glyph, font_width, font_height); + if (__predict_false((attr & TA::Bold))) { + src = src.ConvertToBold(); } - - // 変更可能なグリフ - if (__predict_false(code == 0x5c)) { - if (glyph_5c) { - code = 0x80; - } - } else if (__predict_false(code == 0x7e)) { - if (glyph_7e) { - code = 0x81; - } - } else if (__predict_false(code == 0x7c)) { - if (glyph_7c) { - code = 0x82; - } - } - DrawBitmap(dc, px, py, *glyph[code], attr); + bitmap.DrawBitmapI1(px, py, src, palette); } -// (px, py) を左上とする座標から半角カナ1文字を出力する。 +// (px, py) を左上とする座標から漢字1文字を属性 attr で描画する。 +// sjiscode は Shift_JIS。attr のうち反応するのは Bold のみ。 // フォントサイズは現行のフォント。 void -WXTextPanel::DrawCharKana(wxDC& dc, int px, int py, uint sjiscode, uint attr) +WXTextPanel::DrawChar2(int px, int py, uint sjiscode, uint attr) { - std::unique_ptr kana; - kana.reset(KanaBitmap(sjiscode, attr)); - DrawBitmap(dc, px, py, *kana, attr); -} - -// (px, py) を左上とする座標から漢字1文字を出力する。 -// sjiscode は Shift_JIS。 -// フォントサイズは現行のフォント。 -void -WXTextPanel::DrawChar2(wxDC& dc, int px, int py, uint sjiscode, uint attr) -{ - std::unique_ptr kanji; - kanji.reset(KanjiBitmap(sjiscode, attr)); - DrawBitmap(dc, px, py, *kanji, attr); -} - -// (px, py) を左上とする座標に bitmap を描画する。 -// この DrawBitmap() は dc のペン色を設定して dc.DrawBitmap() を呼ぶ。 -// ちょっと紛らわしいので注意。 -void -WXTextPanel::DrawBitmap(wxDC& dc, int px, int py, const wxBitmap& bitmap, - uint attr) -{ - // 文字の背景は透過ではなく背景色で塗りつぶす - // XXX もっと初期化時に近いところへ移してよさそうだが - dc.SetBackgroundMode(wxSOLID); - - // 属性を設定 - switch (attr) { - case TA::On: - dc.SetTextForeground(text_bgcolor); - dc.SetTextBackground(text_fgcolor); - break; - case TA::Disable: - dc.SetTextForeground(text_disable_color); - dc.SetTextBackground(text_bgcolor); - break; - default: - dc.SetTextForeground(text_fgcolor); - dc.SetTextBackground(text_bgcolor); - break; - } - - // 1文字出力 - dc.DrawBitmap(bitmap, px, py); - - // 1文字ずつ属性を元に戻す - dc.SetTextForeground(text_fgcolor); - dc.SetTextBackground(text_bgcolor); -} - -// Shift_JIS の半角カナ1文字分のビットマップを作成する。 -wxBitmap * -WXTextPanel::KanaBitmap(uint16 sjiscode, uint attr) -{ - const uint8 *base; - // X680x0 CGROM - switch (fontsize) { - case FONT_6x12: - base = BuiltinCGROM::Get6x12(); - break; - case FONT_8x16: - base = BuiltinCGROM::Get8x16(); - break; - default: - __unreachable(); - } - - int bytes = ((font_width + 7) / 8) * font_height; - std::vector buf(bytes); - - const uint8 *ptr; - ptr = base + sjiscode * bytes; - - for (int i = 0; i < bytes; i++) { - buf[i] = bitrev(ptr[i]); - } - if (attr == TA::Em) { - for (int i = 0; i < bytes; i++) { - buf[i] |= buf[i] >> 1; - } + const uint8 *glyph = gFontManager->KanjiGlyph(sjiscode); + BitmapI1 src(glyph, font_width * 2, font_height); + if (__predict_false((attr & TA::Bold))) { + src = src.ConvertToBold(); } - - // その XBM データから1文字分のビットマップオブジェクトを作成 - return new wxBitmap(&buf[0], font_width, font_height, 1); + bitmap.DrawBitmapI1(px, py, src, palette); } - -// Shift_JIS の漢字1文字のビットマップを作成する。 -wxBitmap * -WXTextPanel::KanjiBitmap(uint16 sjiscode, uint attr) -{ - // Shift_JIS を JIS というかコードポイントに変換 - uint sh = (sjiscode >> 8); - uint sl = sjiscode & 0xff; - uint jh; - uint jl; - if (sh < 0xa0) { - jh = sh - 0x71; - } else { - jh = sh - 0xb1; - } - jh = jh * 2 + 1; - jl = sl; - if (sl > 0x7f) { - jl--; - } - if (jl < 0x9e) { - jl -= 0x1f; - } else { - jl -= 0x7d; - jh++; - } - // ここで JIS。これを CGROM 格納コードポイントに変換。 - jh -= 0x21; - jl -= 0x21; - if (jh >= 15) { - jh -= 7; - } - int code = jh * 94 + jl; - - // XXX 見付からなかったらゲタ文字にしたい - if (code <0) code=0x6b; - - // フォント領域 - const uint8 *base; - switch (fontsize) { - case FONT_6x12: - // 12x12 は内蔵フォントデータ - base = builtin_kanji12; - break; - case FONT_8x16: - // 16x16 は X680x0 CGROM のを使う。 - base = BuiltinCGROM::Get16x16(); - break; - default: - // ここより先に必ず半角のほうでエラーが出るはず - __unreachable(); - } - - int bytes = (((font_width * 2) + 7) / 8) * font_height; - std::vector buf(bytes); - - const uint8 *ptr; - ptr = base + code * bytes; - - for (int i = 0; i < bytes; i++) { - buf[i] = bitrev(ptr[i]); - } - if (attr == TA::Em) { - for (int i = 0; i < bytes; i++) { - buf[i] |= buf[i] >> 1; - } - } - - // その XBM データから1文字分のビットマップオブジェクトを作成 - return new wxBitmap(&buf[0], font_width * 2, font_height, 1); -} - -// スタティック変数 -fontsize_t WXTextPanel::global_fontsize; -std::mutex WXTextPanel::global_font_mutex; -u_int WXTextPanel::font_refcnt[FONT_MAX]; -wxBitmap *WXTextPanel::ascii_glyph_table[FONT_MAX][0x83]; -wxBitmap *WXTextPanel::bold_glyph_table[FONT_MAX][0x83];