|
|
1.1 root 1: //
2: // nono
1.1.1.3 ! root 3: // Copyright (C) 2020 nono project
! 4: // Licensed under nono-license.txt
1.1 root 5: //
6:
7: #include "wxlogmonitor.h"
8: #include "logger.h"
9:
10: //
11: // ログモニター
12: //
13:
14: // イベントテーブル
15: wxBEGIN_EVENT_TABLE(WXLogMonitor, inherited)
16: EVT_TIMER(wxID_ANY, WXLogMonitor::OnTimer)
17: wxEND_EVENT_TABLE()
18:
19: // コンストラクタ
20: WXLogMonitor::WXLogMonitor(wxWindow *parent, wxWindowID id)
1.1.1.3 ! root 21: : inherited(parent, id, _("Log"))
1.1 root 22: {
23: col = 80;
24: row = 40;
25:
1.1.1.3 ! root 26: logbuf.reset(new uint8 [row * col]);
! 27: memset(&logbuf[0], 0x20, row * col);
1.1 root 28: text.Init(col, row);
29:
1.1.1.3 ! root 30: wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL);
! 31:
1.1 root 32: // テキストスクリーン
33: screen = new WXTextScreen(this, col, row, text.GetBuf());
1.1.1.3 ! root 34: topsizer->Add(screen, BorderFlags);
! 35:
! 36: SetSizer(topsizer);
1.1 root 37:
38: // 大きさを固定
39: Layout();
40: Fit();
41:
42: // 最初に一度描画しておく。
43: // ウィンドウが表示されてもまだログが出てない場合、タイマーイベントが
44: // おきても更新が起きず、グレーの背景が見えてしまうため。
45: // (ウィンドウの表示が早い場合や、ログレベルが低い場合は有り得る)
46: screen->Refresh();
47:
48: // 更新タイマーは適当な短さにしておく
49: timer.SetOwner(this);
50: timer.Start(10);
51: }
52:
53: // デストラクタ
54: WXLogMonitor::~WXLogMonitor()
55: {
56: }
57:
58: // タイマーイベント
59: void
60: WXLogMonitor::OnTimer(wxTimerEvent& event)
61: {
62: char buf[1024];
63: bool updated = false;
64:
65: // キューから読めるだけ全部ログバッファに書き込む
1.1.1.3 ! root 66: while (gLogger.Read(buf, sizeof(buf))) {
1.1 root 67: Append(buf);
68: updated = true;
69: }
70:
71: // ログの追加がなければここまで
72: if (!updated) {
73: return;
74: }
75:
76: // ここは TextScreen の内部構造に直接書き込むことにする。
77: uint16 *textbuf = text.GetRawBuf();
78:
79: // ログバッファ(循環バッファ)をテキストバッファに再構成。
80: // target は logbuf のうち今表示されるべき一番古い行の先頭を指している
81: // のでこれがテキストバッファの先頭になる。そこから logbuf の末尾まで。
82: // target == 0 の時に限りこの1回のコピーで終わり。それ以外の場合は必ず
83: // logbuf の先頭から target までの後半部分のコピーが発生する。
84: for (int i = 0; i < col * row - target; i++) {
85: textbuf[i] = logbuf[target + i];
86: }
87: if (target != 0) {
88: for (int i = 0; i < target; i++) {
89: textbuf[col * row - target + i] = logbuf[i];
90: }
91: }
92:
93: // 更新指示
94: screen->Refresh();
95: }
96:
97: // フォントサイズ変更
98: void
99: WXLogMonitor::SetFontSize(fontsize_t fontsize)
100: {
101: screen->SetFontSize(fontsize);
102: // ログの再描画は自前で行う必要がある
103: screen->Refresh();
104: // 大きさを変更
105: Layout();
106: Fit();
107: }
108:
109: // 表示用のログバッファに buf を追加
110: //
111: // logbuf は textbuf(, prevbuf) とかと同じ col * row バイトの単純バッファ
112: // 形式。ただしこれを行ごとの循環バッファとして使っていて開始位置が target。
113: // target は logbuf からの距離 (logbuf[] のインデックス) で表し、行は必ず
114: // ウィンドウの行頭から追加することにすると target は col の倍数をとる。
115: //
116: // +---------------------------+
117: // logbuf -> | |
118: // |前行 |
119: // target -> |次に書く行 (今表示されてる一番古い行)
120: // | |
121: // | |
122: // | |
123: // +---------------------------+
124: //
125: // ついでに utfbuf は UTF-8 だが、表示用バッファ(textbuf) は Shift_JIS
126: // なのでここで変換する。
127: void
128: WXLogMonitor::Append(const char *utfbuf)
129: {
130: const char *sjis;
131: int sjislen;
132: int spos;
133:
134: // 文字コードの変換
135: wxString utfstr(utfbuf, wxConvUTF8);
136: sjis = (const char *)utfstr.mb_str(conv);
137: sjislen = strlen(sjis);
138:
139: // XXX 行末残り1桁で漢字が来た場合は?
140:
141: spos = 0;
142: for (;;) {
143: // この行に書き込む長さ
144: int len = std::min(sjislen - spos, col);
145: if (len < 1) {
146: break;
147: }
148:
149: // コピー。残りは空白で埋める
1.1.1.3 ! root 150: memcpy(&logbuf[target], &sjis[spos], len);
1.1 root 151: if (len < col) {
1.1.1.3 ! root 152: memset(&logbuf[target + len], 0x20, col - len);
1.1 root 153: }
154:
155: spos += len;
156: target += col;
157:
158: // 折り返し
159: if (target >= col * row) {
160: target = 0;
161: }
162: }
163: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.