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