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