|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.