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