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

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

unix.superglobalmegacorp.com

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