Annotation of nono/wx/wxtextscreen.cpp, revision 1.1.1.5

1.1       root        1: //
                      2: // nono
1.1.1.2   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
                      7: #include "wxtextscreen.h"
1.1.1.5 ! root        8: #include "wxcolor.h"
1.1.1.3   root        9: #include "wxmainframe.h"
1.1       root       10: #include "bitrev.h"
                     11: #include "cgrom.h"
1.1.1.5 ! root       12: #include "sjis.h"
1.1       root       13: 
                     14: //
1.1.1.3   root       15: // テキストスクリーンを表示するパネル
1.1       root       16: //
                     17: 
                     18: // イベントテーブル
                     19: wxBEGIN_EVENT_TABLE(WXTextScreen, inherited)
                     20:        EVT_PAINT(WXTextScreen::OnPaint)
                     21:        EVT_SIZE(WXTextScreen::OnSize)
1.1.1.3   root       22:        EVT_TIMER(wxID_ANY, WXTextScreen::OnTimer)
1.1       root       23: wxEND_EVENT_TABLE()
                     24: 
                     25: // コンストラクタ
1.1.1.3   root       26: WXTextScreen::WXTextScreen(wxWindow *parent, IMonitor& monitor_)
1.1       root       27:        : inherited(parent)
1.1.1.3   root       28:        , monitor(monitor_)
1.1       root       29: {
1.1.1.3   root       30:        // モニタサイズから初期サイズを決定
                     31:        nnSize ms = monitor.GetMonitorSize();
1.1.1.5 ! root       32:        Init(ms.width, ms.height);
        !            33: 
1.1.1.3   root       34:        wxSize size = wxSize(ms.width * font_width, ms.height * font_height);
                     35:        SetClientSize(size);
1.1.1.5 ! root       36:        SetMinClientSize(size);
1.1.1.3   root       37: 
                     38:        timer.SetOwner(this);
1.1       root       39: 
1.1.1.3   root       40:        // 現在の設定値を適用
                     41:        SetRate(gMainFrame->GetMonitorRate());
                     42: 
                     43:        // 最初に一回描画を起こす
                     44:        wxTimerEvent dummy;
                     45:        AddPendingEvent(dummy);
1.1       root       46: }
                     47: 
                     48: // デストラクタ
                     49: WXTextScreen::~WXTextScreen()
                     50: {
1.1.1.5 ! root       51: }
        !            52: 
        !            53: // (再)初期化
        !            54: void
        !            55: WXTextScreen::Init(int col, int row)
        !            56: {
        !            57:        ts.Init(col, row);
        !            58:        prevbuf.resize(col * row);
        !            59:        std::fill(prevbuf.begin(), prevbuf.end(), 0xffff);
1.1       root       60: }
                     61: 
1.1.1.3   root       62: // 画面更新頻度を Hz で設定する。
1.1       root       63: void
1.1.1.3   root       64: WXTextScreen::SetRate(int hz)
1.1       root       65: {
1.1.1.3   root       66:        timer.Start(1000 / hz);
1.1       root       67: }
                     68: 
                     69: // フォントサイズ変更 (外部インタフェース)
                     70: void
1.1.1.3   root       71: WXTextScreen::SetFontSize(FontId new_fontid)
1.1       root       72: {
                     73:        // 同じなら何もしない
1.1.1.3   root       74:        if (fontid == new_fontid) {
1.1       root       75:                return;
                     76:        }
                     77: 
                     78:        // フォントを更新
1.1.1.3   root       79:        UpdateFont(new_fontid);
1.1       root       80: 
                     81:        // 再描画を強制する。
                     82:        // テキストの桁数行数は変わってないので再確保はしなくていい。
1.1.1.5 ! root       83:        std::fill(prevbuf.begin(), prevbuf.end(), 0xffff);
1.1       root       84: 
                     85:        // コントロールの大きさを変更
1.1.1.5 ! root       86:        wxSize size = wxSize(ts.GetCol() * font_width, ts.GetRow() * font_height);
1.1       root       87:        SetClientSize(size);
1.1.1.5 ! root       88:        SetMinClientSize(size);
1.1       root       89: }
                     90: 
                     91: // サイズ変更イベント
                     92: void
                     93: WXTextScreen::OnSize(wxSizeEvent& event)
                     94: {
                     95:        // Mac ではウィンドウ作成時に 0 以下の値が来ることがある
                     96:        // GTK では 1 で来ることがある
1.1.1.3   root       97:        const wxSize& size = event.GetSize();
1.1       root       98:        if (size.x <= 1 || size.y <= 1) {
                     99:                return;
                    100:        }
                    101: 
1.1.1.3   root      102:        // テキストサイズが変わった時だけテキストバッファを再構成。
                    103:        // (フォントサイズを変えると桁数×行数が変わらず画面サイズが変わる
                    104:        // ということは起きることに注意)
                    105:        int col = size.x / font_width;
                    106:        int row = size.y / font_height;
                    107:        if (col != ts.GetCol() || row != ts.GetRow()) {
1.1.1.5 ! root      108:                Init(col, row);
1.1.1.3   root      109:        }
                    110: 
                    111:        // ビットマップサイズが変わった時だけビットマップバッファを再構成。
1.1.1.5 ! root      112:        wxSize bmpsize = bitmap.GetSize();
        !           113:        wxSize newsize = wxSize(col * font_width, row * font_height);
        !           114:        if (bmpsize != newsize) {
1.1.1.3   root      115:                // ビットマップ作成
1.1.1.5 ! root      116:                bitmap.Create(newsize);
1.1.1.3   root      117:        }
                    118: }
1.1       root      119: 
1.1.1.3   root      120: // タイマーイベント
                    121: void
                    122: WXTextScreen::OnTimer(wxTimerEvent& event)
                    123: {
                    124:        // モニタースクリーンを更新して再描画。
                    125:        monitor.MonitorUpdate(ts);
                    126:        RefreshIfUpdated();
                    127: }
1.1       root      128: 
1.1.1.3   root      129: // 必要なら画面を更新して再描画する
                    130: void
                    131: WXTextScreen::RefreshIfUpdated()
                    132: {
1.1.1.5 ! root      133:        if (ts.GetBuf() != prevbuf) {
1.1.1.3   root      134:                Refresh();
                    135:        }
1.1       root      136: }
                    137: 
                    138: // 描画イベント (UI スレッドから呼ばれる)
                    139: void
                    140: WXTextScreen::OnPaint(wxPaintEvent& event)
                    141: {
1.1.1.3   root      142:        // メモリ DC に描画
1.1       root      143:        wxMemoryDC memDC;
1.1.1.5 ! root      144:        memDC.SelectObject(bitmap);
1.1.1.3   root      145:        // 基本的には RefreshIfUpdated() により更新があった時だけ呼ばれる
                    146:        Draw(memDC);
1.1       root      147: 
                    148:        // 実画面 DC にコピー
                    149:        wxPaintDC dstDC(this);
1.1.1.5 ! root      150:        wxSize size = bitmap.GetSize();
        !           151:        dstDC.Blit(0, 0, size.x, size.y, &memDC, 0, 0);
1.1       root      152: }
                    153: 
                    154: // テキストバッファの内容をパネルのバックグラウンドバッファに描画する。
                    155: void
                    156: WXTextScreen::Draw(wxDC& dc)
                    157: {
1.1.1.5 ! root      158:        auto text = ts.GetBuf().begin();
        !           159:        auto prev = prevbuf.begin();
        !           160: 
1.1.1.3   root      161:        int col = ts.GetCol();
                    162:        int row = ts.GetRow();
1.1       root      163:        int px = 0;
                    164:        int py = 0;
1.1.1.5 ! root      165:        uint prevattr = (uint)-1;
        !           166: 
1.1       root      167:        for (int y = 0; y < row; y++, py += font_height) {
                    168:                px = 0;
                    169:                for (int x = 0; x < col; ) {
                    170:                        uint16 data = *text;
                    171:                        uint attr = (data & 0xff00);
                    172:                        uint chr  = (data & 0xff);
1.1.1.5 ! root      173: 
        !           174:                        // 属性(色)を変更
        !           175:                        if (__predict_false(attr != prevattr)) {
        !           176:                                switch (attr) {
        !           177:                                 case TA::On:
        !           178:                                        SetTextColor(BGPANEL, *wxBLACK);
        !           179:                                        break;
        !           180:                                 case TA::Disable:
        !           181:                                        SetTextColor(UD_GREY, BGPANEL);
        !           182:                                        break;
        !           183:                                 default:
        !           184:                                        ResetTextColor();
        !           185:                                        break;
        !           186:                                }
        !           187:                                prevattr = attr;
        !           188:                        }
        !           189: 
        !           190:                        if (__predict_true(SJIS::IsHankaku(chr))) {
        !           191:                                // 半角文字
1.1       root      192:                                if (*prev != data) {
1.1.1.5 ! root      193:                                        DrawChar1(dc, px, py, chr, attr);
        !           194:                                        if (SJIS::IsZenkaku(*prev) && x < col - 1) {
        !           195:                                                // 変更前が全角文字だったら 2 バイト目も消す
1.1.1.4   root      196:                                                prev[1] = 0;
                    197:                                        }
1.1       root      198:                                        *prev = data;
                    199:                                }
1.1.1.5 ! root      200:                                prev += 1;
        !           201:                                text += 1;
        !           202:                                x += 1;
        !           203:                                px += font_width * 1;
1.1       root      204:                        } else {
1.1.1.5 ! root      205:                                // 全角文字
        !           206:                                // XXX: 最右カラムだったら?
        !           207:                                if (*prev != data || prev[1] != text[1]) {
        !           208:                                        uint code = (chr << 8) | (text[1] & 0xff);
1.1       root      209:                                        DrawChar2(dc, px, py, code, attr);
1.1.1.5 ! root      210:                                        if (SJIS::IsASCII(*prev) && SJIS::IsZenkaku(prev[1])
        !           211:                                         && x < col - 2) {
        !           212:                                                // 変更前が 'Aあ' だったら'あ'の2バイト目も消す
        !           213:                                                prev[2] = 0;
        !           214:                                        }
        !           215:                                        prev[0] = data;
        !           216:                                        prev[1] = text[1];
1.1       root      217:                                }
1.1.1.5 ! root      218:                                prev += 2;
        !           219:                                text += 2;
1.1       root      220:                                x += 2;
                    221:                                px += font_width * 2;
                    222:                        }
                    223:                }
                    224:        }
                    225: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.