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

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.3   root       13: #include "wxmainframe.h"
1.1.1.5   root       14: #include "sjis.h"
1.1.1.8   root       15: PRAGMA_PUSH_WARNINGS
                     16: #include <wx/clipbrd.h>
                     17: PRAGMA_POP_WARNINGS
1.1       root       18: 
                     19: // イベントテーブル
                     20: wxBEGIN_EVENT_TABLE(WXTextScreen, inherited)
                     21:        EVT_SIZE(WXTextScreen::OnSize)
1.1.1.8   root       22:        EVT_MENU(wxID_COPY, WXTextScreen::OnCopy)
1.1       root       23: wxEND_EVENT_TABLE()
                     24: 
                     25: // コンストラクタ
1.1.1.9   root       26: WXTextScreen::WXTextScreen(wxWindow *parent, const nnSize& screensize)
1.1       root       27:        : inherited(parent)
                     28: {
1.1.1.12  root       29:        SetName("WXTextScreen");
                     30: 
1.1.1.8   root       31:        pad_left   = DefaultPadding;
                     32:        pad_top    = DefaultPadding;
                     33:        pad_right  = DefaultPadding;
                     34:        pad_bottom = DefaultPadding;
                     35: 
1.1.1.9   root       36:        Init(screensize.width, screensize.height);
1.1.1.5   root       37: 
1.1.1.8   root       38:        FontChanged();
                     39: 
                     40:        // コンテキストメニューイベントを動的に追加
                     41:        // (コンテキストメニューを表示したくない人があとから外せるようにするため)
                     42:        ConnectContextMenu();
1.1       root       43: }
                     44: 
                     45: // デストラクタ
                     46: WXTextScreen::~WXTextScreen()
                     47: {
1.1.1.5   root       48: }
                     49: 
                     50: // (再)初期化
                     51: void
                     52: WXTextScreen::Init(int col, int row)
                     53: {
1.1.1.9   root       54:        screen.Init(col, row);
1.1.1.5   root       55:        prevbuf.resize(col * row);
1.1.1.8   root       56:        InvalidateText();
                     57: }
                     58: 
                     59: // テキスト画面全体が次回再描画されるようにする
                     60: void
                     61: WXTextScreen::InvalidateText()
                     62: {
1.1.1.5   root       63:        std::fill(prevbuf.begin(), prevbuf.end(), 0xffff);
1.1       root       64: }
                     65: 
                     66: // フォントサイズ変更 (外部インタフェース)
                     67: void
1.1.1.8   root       68: WXTextScreen::FontChanged()
1.1       root       69: {
1.1.1.8   root       70:        inherited::FontChanged();
1.1       root       71: 
                     72:        // 再描画を強制する。
                     73:        // テキストの桁数行数は変わってないので再確保はしなくていい。
1.1.1.8   root       74:        InvalidateText();
1.1       root       75: 
                     76:        // コントロールの大きさを変更
1.1.1.13  root       77:        Fit();
1.1.1.8   root       78: }
                     79: 
                     80: void
1.1.1.13  root       81: WXTextScreen::Fit()
1.1.1.8   root       82: {
1.1.1.13  root       83:        // 指定の (row, col) にパディングを加味した大きさにする、
                     84:        // なので GetSize() ではない。
                     85:        wxSize size(GetScreenWidth(GetCol()), GetScreenHeight(GetRow()));
                     86: 
                     87:        // バックバッファのサイズを固定。
                     88:        SetMinBitmapSize(size);
                     89: 
                     90:        SetSize(size);
                     91:        SetMinSize(size);
1.1       root       92: }
                     93: 
                     94: void
                     95: WXTextScreen::OnSize(wxSizeEvent& event)
                     96: {
1.1.1.13  root       97:        const wxSize& size = GetSize();
1.1.1.8   root       98: 
1.1.1.3   root       99:        // テキストサイズが変わった時だけテキストバッファを再構成。
                    100:        // (フォントサイズを変えると桁数×行数が変わらず画面サイズが変わる
                    101:        // ということは起きることに注意)
1.1.1.8   root      102:        int sw = size.x - pad_left - pad_right;
                    103:        int sh = size.y - pad_top - pad_bottom;
1.1.1.13  root      104:        int col = (font_width != 0)  ? (sw / font_width)  : 0;
                    105:        int row = (font_height != 0) ? (sh / font_height) : 0;
                    106:        if (__predict_false(col < 1 || row < 1)) {
                    107:                return;
1.1.1.8   root      108:        }
1.1.1.13  root      109: 
1.1.1.9   root      110:        if (col != screen.GetCol() || row != screen.GetRow()) {
1.1.1.5   root      111:                Init(col, row);
1.1.1.8   root      112:        } else {
                    113:                // テキストバッファを再構成しなくても全域を再描画する必要がある
                    114:                InvalidateText();
1.1.1.3   root      115:        }
1.1.1.14  root      116:        // サイズが変わったらどちらにしてもパディングも塗り直す。
                    117:        draw_padding = true;
1.1.1.13  root      118: 
                    119:        event.Skip();
1.1.1.3   root      120: }
1.1       root      121: 
                    122: // テキストバッファの内容をパネルのバックグラウンドバッファに描画する。
                    123: void
1.1.1.8   root      124: WXTextScreen::Draw()
1.1       root      125: {
1.1.1.14  root      126:        if (__predict_false(draw_padding)) {
                    127:                draw_padding = false;
                    128:                auto bgcol = GetTextBackColor();
                    129:                // パディングを塗るだけでいいのだが手抜き。
                    130:                bitmap.Fill(bgcol);
                    131:        }
                    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: 
1.1.1.13  root      216: // 桁数が col_ の時の横幅 [pixel] を取得。
                    217: int
                    218: WXTextScreen::GetScreenWidth(int col_) const
                    219: {
1.1.1.14  root      220:        int w = GetFontWidth() * col_ + GetPaddingX();
1.1.1.13  root      221:        return w;
                    222: }
                    223: 
                    224: // 行数が row_ の時の高さ [pixel] を取得。
                    225: int
                    226: WXTextScreen::GetScreenHeight(int row_) const
                    227: {
1.1.1.14  root      228:        int h = GetFontHeight() * row_ + GetPaddingY();
1.1.1.13  root      229:        return h;
                    230: }
                    231: 
1.1.1.8   root      232: // パディングサイズ変更。
                    233: // 負数なら変更しない。
                    234: void
                    235: WXTextScreen::SetPadding(int l, int t, int r, int b)
                    236: {
                    237:        if (l >= 0) {
                    238:                pad_left = l;
                    239:        }
                    240:        if (t >= 0) {
                    241:                pad_top = t;
                    242:        }
                    243:        if (r >= 0) {
                    244:                pad_right = r;
                    245:        }
                    246:        if (b >= 0) {
                    247:                pad_bottom = b;
                    248:        }
                    249: 
1.1.1.13  root      250:        Fit();
1.1.1.10  root      251: }
                    252: 
1.1.1.8   root      253: // クライアント座標 pos をテキスト座標(桁、行)に変換して返す
                    254: // パディング(上と左)領域では戻り値が負数になることに注意。
                    255: wxPoint
                    256: WXTextScreen::GetTextPosition(const wxPoint& pos) const
                    257: {
                    258:        wxPoint tpos;
                    259: 
                    260:        tpos.x = (pos.x - pad_left) / GetFontWidth();
                    261:        tpos.y = (pos.y - pad_top)  / GetFontHeight();
                    262: 
                    263:        return tpos;
                    264: }
                    265: 
                    266: // コンテキストメニューイベントを接続
                    267: void
                    268: WXTextScreen::ConnectContextMenu()
                    269: {
                    270:        Connect(wxEVT_CONTEXT_MENU,
                    271:                wxContextMenuEventHandler(WXTextScreen::OnContextMenu), NULL, this);
                    272: }
                    273: 
                    274: // コンテキストメニューイベントを接続解除
                    275: void
                    276: WXTextScreen::DisconnectContextMenu()
                    277: {
                    278:        Disconnect(wxEVT_CONTEXT_MENU,
                    279:                wxContextMenuEventHandler(WXTextScreen::OnContextMenu), NULL, this);
                    280: }
                    281: 
                    282: // コンテキストメニューイベント
                    283: void
                    284: WXTextScreen::OnContextMenu(wxContextMenuEvent& ev)
                    285: {
                    286:        wxMenu *menu = new wxMenu();
                    287: 
1.1.1.13  root      288:        menu->Append(wxID_COPY, _("&Copy All"));
1.1.1.8   root      289: 
                    290:        PopupMenu(menu);
                    291: }
                    292: 
                    293: // コンテキストメニュー「コピー」イベント
                    294: void
                    295: WXTextScreen::OnCopy(wxCommandEvent& ev)
                    296: {
1.1.1.9   root      297:        int col = screen.GetCol();
                    298:        int row = screen.GetRow();
1.1.1.8   root      299: 
1.1.1.9   root      300:        const std::vector<uint16>& src = screen.GetBuf();
1.1.1.8   root      301:        auto s = src.begin();
                    302: 
                    303:        std::vector<uint8> buf;
                    304: 
                    305:        for (int y = 0; y < row; y++) {
                    306:                for (int x = 0; x < col; x++) {
                    307:                        // 下位バイトだけ取り出すと SJIS 文字列になる
                    308:                        buf.push_back((*s++) & 0xff);
                    309:                }
                    310:                // 末尾の空白を取り除く
                    311:                while (buf.back() == ' ') {
                    312:                        buf.pop_back();
                    313:                }
                    314:                buf.push_back('\n');
                    315:        }
                    316:        buf.push_back('\0');
                    317: 
                    318: #if 0
                    319:        // Shift_JIS を UTF-8 に変換
                    320:        // XXX 今はまだ Shift_JIS 出してる人がいない
                    321: #else
                    322:        wxString text(buf.data());
                    323: #endif
                    324: 
                    325:        // クリップボードへ転送
                    326:        if (wxTheClipboard->Open()) {
                    327:                auto obj = new wxTextDataObject(text);
                    328:                wxTheClipboard->UsePrimarySelection(false);
                    329:                wxTheClipboard->SetData(obj);
                    330:                wxTheClipboard->Close();
                    331:        }
                    332: #if defined(__WXGTK__)
                    333:        // wxGTK なら X11 のクリップボードにも同じものを入れる。
                    334:        // UsePrimarySelection(false) だと GTK のクリップボードに入り、
                    335:        // UsePrimarySelection(true) だと X11 のクリップボードに入る。
                    336:        // X11 用語では「カットバッファ/セレクション」というらしく、
                    337:        // 実は8つくらいあってその1つ目なので PrimarySelection らしい。
                    338:        if (wxTheClipboard->Open()) {
                    339:                auto obj = new wxTextDataObject(text);
                    340:                wxTheClipboard->UsePrimarySelection(true);
                    341:                wxTheClipboard->SetData(obj);
                    342:                wxTheClipboard->Close();
                    343:        }
                    344: #endif
                    345: }

unix.superglobalmegacorp.com

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