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

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: 
1.1.1.8   root        7: //
                      8: // テキストスクリーンを描画するパネル
                      9: //
                     10: 
1.1       root       11: #include "wxtextscreen.h"
1.1.1.8   root       12: #include "fontmanager.h"
1.1.1.5   root       13: #include "wxcolor.h"
1.1.1.3   root       14: #include "wxmainframe.h"
1.1.1.5   root       15: #include "sjis.h"
1.1.1.8   root       16: PRAGMA_PUSH_WARNINGS
                     17: #include <wx/clipbrd.h>
                     18: PRAGMA_POP_WARNINGS
1.1       root       19: 
                     20: // イベントテーブル
                     21: wxBEGIN_EVENT_TABLE(WXTextScreen, inherited)
                     22:        EVT_SIZE(WXTextScreen::OnSize)
1.1.1.8   root       23:        EVT_MENU(wxID_COPY, WXTextScreen::OnCopy)
1.1       root       24: wxEND_EVENT_TABLE()
                     25: 
                     26: // コンストラクタ
1.1.1.9 ! root       27: WXTextScreen::WXTextScreen(wxWindow *parent, const nnSize& screensize)
1.1       root       28:        : inherited(parent)
                     29: {
1.1.1.8   root       30:        pad_left   = DefaultPadding;
                     31:        pad_top    = DefaultPadding;
                     32:        pad_right  = DefaultPadding;
                     33:        pad_bottom = DefaultPadding;
                     34: 
1.1.1.9 ! root       35:        Init(screensize.width, screensize.height);
1.1.1.5   root       36: 
1.1.1.8   root       37:        FontChanged();
                     38: 
                     39:        // コンテキストメニューイベントを動的に追加
                     40:        // (コンテキストメニューを表示したくない人があとから外せるようにするため)
                     41:        ConnectContextMenu();
1.1       root       42: }
                     43: 
                     44: // デストラクタ
                     45: WXTextScreen::~WXTextScreen()
                     46: {
1.1.1.5   root       47: }
                     48: 
                     49: // (再)初期化
                     50: void
                     51: WXTextScreen::Init(int col, int row)
                     52: {
1.1.1.9 ! root       53:        screen.Init(col, row);
1.1.1.5   root       54:        prevbuf.resize(col * row);
1.1.1.8   root       55:        InvalidateText();
                     56: }
                     57: 
                     58: // テキスト画面全体が次回再描画されるようにする
                     59: void
                     60: WXTextScreen::InvalidateText()
                     61: {
1.1.1.5   root       62:        std::fill(prevbuf.begin(), prevbuf.end(), 0xffff);
1.1       root       63: }
                     64: 
                     65: // フォントサイズ変更 (外部インタフェース)
                     66: void
1.1.1.8   root       67: WXTextScreen::FontChanged()
1.1       root       68: {
1.1.1.8   root       69:        inherited::FontChanged();
1.1       root       70: 
                     71:        // 再描画を強制する。
                     72:        // テキストの桁数行数は変わってないので再確保はしなくていい。
1.1.1.8   root       73:        InvalidateText();
1.1       root       74: 
                     75:        // コントロールの大きさを変更
1.1.1.8   root       76:        DoSize();
                     77: }
                     78: 
                     79: // (自発的な)サイズ変更。
1.1.1.9 ! root       80: // screen の行数桁数、font_{width,height}、四方のパディングのいずれかが
1.1.1.8   root       81: // 変わった場合に呼ぶこと。
                     82: void
                     83: WXTextScreen::DoSize()
                     84: {
                     85:        wxSize size = wxSize(
1.1.1.9 ! root       86:                screen.GetCol() * font_width + pad_left + pad_right,
        !            87:                screen.GetRow() * font_height + pad_top + pad_bottom);
1.1       root       88:        SetClientSize(size);
1.1.1.5   root       89:        SetMinClientSize(size);
1.1       root       90: }
                     91: 
                     92: // サイズ変更イベント
                     93: void
                     94: WXTextScreen::OnSize(wxSizeEvent& event)
                     95: {
1.1.1.9 ! root       96:        // Mac ではウィンドウ作成時に 0 以下の値が来ることがある。
        !            97:        // GTK では 1 で来ることがある。
1.1.1.3   root       98:        const wxSize& size = event.GetSize();
1.1       root       99:        if (size.x <= 1 || size.y <= 1) {
                    100:                return;
                    101:        }
                    102: 
1.1.1.8   root      103:        // 親クラス
                    104:        inherited::OnSize(event);
                    105: 
1.1.1.3   root      106:        // テキストサイズが変わった時だけテキストバッファを再構成。
                    107:        // (フォントサイズを変えると桁数×行数が変わらず画面サイズが変わる
                    108:        // ということは起きることに注意)
1.1.1.8   root      109:        int sw = size.x - pad_left - pad_right;
                    110:        int sh = size.y - pad_top - pad_bottom;
                    111:        if (__predict_false(sw < 0)) {
                    112:                sw = 0;
                    113:        }
                    114:        if (__predict_false(sh < 0)) {
                    115:                sh = 0;
                    116:        }
                    117:        int col = sw / font_width;
                    118:        int row = sh / font_height;
1.1.1.9 ! root      119:        if (col != screen.GetCol() || row != screen.GetRow()) {
1.1.1.5   root      120:                Init(col, row);
1.1.1.8   root      121:        } else {
                    122:                // テキストバッファを再構成しなくても全域を再描画する必要がある
                    123:                InvalidateText();
1.1.1.3   root      124:        }
                    125: }
1.1       root      126: 
                    127: // テキストバッファの内容をパネルのバックグラウンドバッファに描画する。
                    128: void
1.1.1.8   root      129: WXTextScreen::Draw()
1.1       root      130: {
1.1.1.9 ! root      131:        auto text = screen.GetBuf().begin();
1.1.1.5   root      132:        auto prev = prevbuf.begin();
                    133: 
1.1.1.9 ! root      134:        int col = screen.GetCol();
        !           135:        int row = screen.GetRow();
1.1.1.5   root      136:        uint prevattr = (uint)-1;
                    137: 
1.1.1.8   root      138:        int py = pad_top;
1.1       root      139:        for (int y = 0; y < row; y++, py += font_height) {
1.1.1.8   root      140:                int px = pad_left;
1.1       root      141:                for (int x = 0; x < col; ) {
                    142:                        uint16 data = *text;
                    143:                        uint attr = (data & 0xff00);
                    144:                        uint chr  = (data & 0xff);
1.1.1.5   root      145: 
                    146:                        // 属性(色)を変更
                    147:                        if (__predict_false(attr != prevattr)) {
                    148:                                switch (attr) {
                    149:                                 case TA::On:
1.1.1.8   root      150:                                        SetTextColor(BGPANEL, UD_BLACK);
1.1.1.5   root      151:                                        break;
1.1.1.7   root      152:                                 case TA::Off:
1.1.1.8   root      153:                                        SetTextColor(UD_BLACK, UD_LIGHT_GREY);
1.1.1.7   root      154:                                        break;
1.1.1.5   root      155:                                 case TA::Disable:
                    156:                                        SetTextColor(UD_GREY, BGPANEL);
                    157:                                        break;
                    158:                                 default:
                    159:                                        ResetTextColor();
                    160:                                        break;
                    161:                                }
                    162:                                prevattr = attr;
                    163:                        }
                    164: 
                    165:                        if (__predict_true(SJIS::IsHankaku(chr))) {
                    166:                                // 半角文字
1.1       root      167:                                if (*prev != data) {
1.1.1.8   root      168:                                        DrawChar1(px, py, chr, attr);
                    169: 
1.1.1.5   root      170:                                        if (SJIS::IsZenkaku(*prev) && x < col - 1) {
                    171:                                                // 変更前が全角文字だったら 2 バイト目も消す
1.1.1.4   root      172:                                                prev[1] = 0;
                    173:                                        }
1.1       root      174:                                        *prev = data;
                    175:                                }
1.1.1.5   root      176:                                prev += 1;
                    177:                                text += 1;
                    178:                                x += 1;
                    179:                                px += font_width * 1;
1.1       root      180:                        } else {
1.1.1.5   root      181:                                // 全角文字
1.1.1.6   root      182:                                // XXX: 最右カラムだったら?
1.1.1.5   root      183:                                if (*prev != data || prev[1] != text[1]) {
                    184:                                        uint code = (chr << 8) | (text[1] & 0xff);
1.1.1.8   root      185:                                        DrawChar2(px, py, code, attr);
                    186: 
1.1.1.5   root      187:                                        if (SJIS::IsASCII(*prev) && SJIS::IsZenkaku(prev[1])
                    188:                                         && x < col - 2) {
1.1.1.6   root      189:                                                // 変更前が 'Aあ' だったら'あ'の2バイト目も消す
1.1.1.5   root      190:                                                prev[2] = 0;
                    191:                                        }
                    192:                                        prev[0] = data;
                    193:                                        prev[1] = text[1];
1.1       root      194:                                }
1.1.1.5   root      195:                                prev += 2;
                    196:                                text += 2;
1.1       root      197:                                x += 2;
                    198:                                px += font_width * 2;
                    199:                        }
                    200:                }
                    201:        }
                    202: }
1.1.1.8   root      203: 
                    204: // パディングサイズ変更。
                    205: // 負数なら変更しない。
                    206: void
                    207: WXTextScreen::SetPadding(int l, int t, int r, int b)
                    208: {
                    209:        if (l >= 0) {
                    210:                pad_left = l;
                    211:        }
                    212:        if (t >= 0) {
                    213:                pad_top = t;
                    214:        }
                    215:        if (r >= 0) {
                    216:                pad_right = r;
                    217:        }
                    218:        if (b >= 0) {
                    219:                pad_bottom = b;
                    220:        }
                    221: 
                    222:        DoSize();
                    223: }
                    224: 
                    225: // クライアント座標 pos をテキスト座標(桁、行)に変換して返す
                    226: // パディング(上と左)領域では戻り値が負数になることに注意。
                    227: wxPoint
                    228: WXTextScreen::GetTextPosition(const wxPoint& pos) const
                    229: {
                    230:        wxPoint tpos;
                    231: 
                    232:        tpos.x = (pos.x - pad_left) / GetFontWidth();
                    233:        tpos.y = (pos.y - pad_top)  / GetFontHeight();
                    234: 
                    235:        return tpos;
                    236: }
                    237: 
                    238: // コンテキストメニューイベントを接続
                    239: void
                    240: WXTextScreen::ConnectContextMenu()
                    241: {
                    242:        Connect(wxEVT_CONTEXT_MENU,
                    243:                wxContextMenuEventHandler(WXTextScreen::OnContextMenu), NULL, this);
                    244: }
                    245: 
                    246: // コンテキストメニューイベントを接続解除
                    247: void
                    248: WXTextScreen::DisconnectContextMenu()
                    249: {
                    250:        Disconnect(wxEVT_CONTEXT_MENU,
                    251:                wxContextMenuEventHandler(WXTextScreen::OnContextMenu), NULL, this);
                    252: }
                    253: 
                    254: // コンテキストメニューイベント
                    255: void
                    256: WXTextScreen::OnContextMenu(wxContextMenuEvent& ev)
                    257: {
                    258:        wxMenu *menu = new wxMenu();
                    259: 
                    260:        menu->Append(wxID_COPY, _T("&Copy"));
                    261: 
                    262:        PopupMenu(menu);
                    263: }
                    264: 
                    265: // コンテキストメニュー「コピー」イベント
                    266: void
                    267: WXTextScreen::OnCopy(wxCommandEvent& ev)
                    268: {
1.1.1.9 ! root      269:        int col = screen.GetCol();
        !           270:        int row = screen.GetRow();
1.1.1.8   root      271: 
1.1.1.9 ! root      272:        const std::vector<uint16>& src = screen.GetBuf();
1.1.1.8   root      273:        auto s = src.begin();
                    274: 
                    275:        std::vector<uint8> buf;
                    276: 
                    277:        for (int y = 0; y < row; y++) {
                    278:                for (int x = 0; x < col; x++) {
                    279:                        // 下位バイトだけ取り出すと SJIS 文字列になる
                    280:                        buf.push_back((*s++) & 0xff);
                    281:                }
                    282:                // 末尾の空白を取り除く
                    283:                while (buf.back() == ' ') {
                    284:                        buf.pop_back();
                    285:                }
                    286:                buf.push_back('\n');
                    287:        }
                    288:        buf.push_back('\0');
                    289: 
                    290: #if 0
                    291:        // Shift_JIS を UTF-8 に変換
                    292:        // XXX 今はまだ Shift_JIS 出してる人がいない
                    293: #else
                    294:        wxString text(buf.data());
                    295: #endif
                    296: 
                    297:        // クリップボードへ転送
                    298:        if (wxTheClipboard->Open()) {
                    299:                auto obj = new wxTextDataObject(text);
                    300:                wxTheClipboard->UsePrimarySelection(false);
                    301:                wxTheClipboard->SetData(obj);
                    302:                wxTheClipboard->Close();
                    303:        }
                    304: #if defined(__WXGTK__)
                    305:        // wxGTK なら X11 のクリップボードにも同じものを入れる。
                    306:        // UsePrimarySelection(false) だと GTK のクリップボードに入り、
                    307:        // UsePrimarySelection(true) だと X11 のクリップボードに入る。
                    308:        // X11 用語では「カットバッファ/セレクション」というらしく、
                    309:        // 実は8つくらいあってその1つ目なので PrimarySelection らしい。
                    310:        if (wxTheClipboard->Open()) {
                    311:                auto obj = new wxTextDataObject(text);
                    312:                wxTheClipboard->UsePrimarySelection(true);
                    313:                wxTheClipboard->SetData(obj);
                    314:                wxTheClipboard->Close();
                    315:        }
                    316: #endif
                    317: }

unix.superglobalmegacorp.com

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