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

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

unix.superglobalmegacorp.com

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