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

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

unix.superglobalmegacorp.com

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