|
|
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:
7: #include "wxtextscreen.h"
1.1.1.3 root 8: #include "wxmainframe.h"
1.1 root 9: #include "bitrev.h"
10: #include "cgrom.h"
11:
12: //
1.1.1.3 root 13: // テキストスクリーンを表示するパネル
1.1 root 14: //
15:
16: // イベントテーブル
17: wxBEGIN_EVENT_TABLE(WXTextScreen, inherited)
18: EVT_PAINT(WXTextScreen::OnPaint)
19: EVT_SIZE(WXTextScreen::OnSize)
1.1.1.3 root 20: EVT_TIMER(wxID_ANY, WXTextScreen::OnTimer)
1.1 root 21: wxEND_EVENT_TABLE()
22:
23: // コンストラクタ
1.1.1.3 root 24: WXTextScreen::WXTextScreen(wxWindow *parent, IMonitor& monitor_)
1.1 root 25: : inherited(parent)
1.1.1.3 root 26: , monitor(monitor_)
1.1 root 27: {
1.1.1.3 root 28: // モニタサイズから初期サイズを決定
29: nnSize ms = monitor.GetMonitorSize();
30: wxSize size = wxSize(ms.width * font_width, ms.height * font_height);
31: SetClientSize(size);
32: SetMinSize(size);
33:
34: timer.SetOwner(this);
1.1 root 35:
1.1.1.3 root 36: // 現在の設定値を適用
37: SetRate(gMainFrame->GetMonitorRate());
38:
39: // 最初に一回描画を起こす
40: wxTimerEvent dummy;
41: AddPendingEvent(dummy);
1.1 root 42: }
43:
44: // デストラクタ
45: WXTextScreen::~WXTextScreen()
46: {
1.1.1.2 root 47: bitmap.reset();
48: image.reset();
49: bmpbuf.reset();
50: prevbuf.reset();
1.1 root 51: }
52:
1.1.1.3 root 53: // 画面更新頻度を Hz で設定する。
1.1 root 54: void
1.1.1.3 root 55: WXTextScreen::SetRate(int hz)
1.1 root 56: {
1.1.1.3 root 57: timer.Start(1000 / hz);
1.1 root 58: }
59:
60: // フォントサイズ変更 (外部インタフェース)
61: void
1.1.1.3 root 62: WXTextScreen::SetFontSize(FontId new_fontid)
1.1 root 63: {
64: // 同じなら何もしない
1.1.1.3 root 65: if (fontid == new_fontid) {
1.1 root 66: return;
67: }
68:
69: // フォントを更新
1.1.1.3 root 70: UpdateFont(new_fontid);
1.1 root 71:
72: // 再描画を強制する。
73: // テキストの桁数行数は変わってないので再確保はしなくていい。
1.1.1.3 root 74: int col = ts.GetCol();
75: int row = ts.GetRow();
1.1.1.2 root 76: assert((bool)prevbuf);
77: memset(&prevbuf[0], 0xff, col * row * sizeof(prevbuf[0]));
1.1 root 78:
79: // コントロールの大きさを変更
80: wxSize size = wxSize(col * font_width, row * font_height);
81: SetClientSize(size);
82: SetMinSize(size);
83: }
84:
85: // サイズ変更イベント
86: void
87: WXTextScreen::OnSize(wxSizeEvent& event)
88: {
89: // Mac ではウィンドウ作成時に 0 以下の値が来ることがある
90: // GTK では 1 で来ることがある
1.1.1.3 root 91: const wxSize& size = event.GetSize();
1.1 root 92: if (size.x <= 1 || size.y <= 1) {
93: return;
94: }
95:
1.1.1.3 root 96: // テキストサイズが変わった時だけテキストバッファを再構成。
97: // (フォントサイズを変えると桁数×行数が変わらず画面サイズが変わる
98: // ということは起きることに注意)
99: int col = size.x / font_width;
100: int row = size.y / font_height;
101: if (col != ts.GetCol() || row != ts.GetRow()) {
102: ts.Init(col, row);
103: prevbuf.reset(new uint16 [col * row]);
104: memset(&prevbuf[0], 0xff, col * row * sizeof(prevbuf[0]));
105: }
106:
107: // ビットマップサイズが変わった時だけビットマップバッファを再構成。
108: if (col * font_width != view_width || row * font_height != view_height) {
109: // ビットマップを持っていれば (この順序で) 一旦解放
110: bitmap.reset();
111: image.reset();
112: bmpbuf.reset();
113:
114: // ビットマップ作成
115: view_width = col * font_width;
116: view_height = row * font_height;
117: bmpbuf.reset(new uint8 [view_width * view_height * 3]);
118: // 正しく描かれなかった時に分かりやすいよう初期値は濃いグレーにしておく
119: memset(&bmpbuf[0], 0x70, view_width * view_height * 3);
120: image.reset(new wxImage(view_width, view_height, bmpbuf.get(), true));
121: bitmap.reset(new wxBitmap(*image));
122: }
123: }
1.1 root 124:
1.1.1.3 root 125: // タイマーイベント
126: void
127: WXTextScreen::OnTimer(wxTimerEvent& event)
128: {
129: // モニタースクリーンを更新して再描画。
130: monitor.MonitorUpdate(ts);
131: RefreshIfUpdated();
132: }
1.1 root 133:
1.1.1.3 root 134: // 必要なら画面を更新して再描画する
135: void
136: WXTextScreen::RefreshIfUpdated()
137: {
138: int len = ts.GetCol() * ts.GetRow() * sizeof(prevbuf[0]);
139: if (memcmp(ts.GetBuf(), &prevbuf[0], len) != 0) {
140: Refresh();
141: }
1.1 root 142: }
143:
144: // 描画イベント (UI スレッドから呼ばれる)
145: void
146: WXTextScreen::OnPaint(wxPaintEvent& event)
147: {
1.1.1.3 root 148: // メモリ DC に描画
1.1 root 149: wxMemoryDC memDC;
150: memDC.SelectObject(*bitmap);
1.1.1.3 root 151: // 基本的には RefreshIfUpdated() により更新があった時だけ呼ばれる
152: Draw(memDC);
1.1 root 153:
154: // 実画面 DC にコピー
155: wxPaintDC dstDC(this);
156: dstDC.Blit(0, 0, view_width, view_height, &memDC, 0, 0);
157: }
158:
159: // テキストバッファの内容をパネルのバックグラウンドバッファに描画する。
160: void
161: WXTextScreen::Draw(wxDC& dc)
162: {
1.1.1.3 root 163: const uint16 *text = ts.GetBuf();
1.1.1.2 root 164: uint16 *prev = &prevbuf[0];
1.1.1.3 root 165: int col = ts.GetCol();
166: int row = ts.GetRow();
1.1 root 167: int px = 0;
168: int py = 0;
169: for (int y = 0; y < row; y++, py += font_height) {
170: px = 0;
171: for (int x = 0; x < col; ) {
172: uint16 data = *text;
173: uint attr = (data & 0xff00);
174: uint chr = (data & 0xff);
175: if (__predict_true(chr < 128)) {
176: // ASCII
177: if (*prev != data) {
1.1.1.4 ! root 178: if (*prev >= 128 && x != col - 1) {
! 179: // prev がマルチバイトだったときは 2byte 目も消す
! 180: prev[1] = 0;
! 181: }
1.1 root 182: DrawChar1(dc, px, py, chr, attr);
183: *prev = data;
184: }
185: prev++;
186: text++;
187: x++;
188: px += font_width;
189: } else {
190: // マルチバイト文字は Shift_JIS として処理する
191: uint code = (chr << 8) | (text[1] & 0xff);
1.1.1.3 root 192: if (prev[0] != data || prev[1] != text[1]) {
1.1 root 193: DrawChar2(dc, px, py, code, attr);
194: }
195: *prev++ = *text++;
196: *prev++ = *text++;
197: x += 2;
198: px += font_width * 2;
199: }
200: }
201: }
202: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.