|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2022 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // ログレベル設定ウィンドウ
9: //
10:
11: #include "wxlogsetting.h"
12: #include "wxcolor.h"
13: #include "wxtextscreen.h"
14: #include "mainapp.h"
15: #include <algorithm>
16:
17: //
18: // パネル部分
19: //
20:
21: // イベントテーブル
22: wxBEGIN_EVENT_TABLE(WXLogSettingPanel, inherited)
23: EVT_LEFT_DOWN(WXLogSettingPanel::OnLeftDown)
24: EVT_LEFT_UP(WXLogSettingPanel::OnLeftUp)
25: wxEND_EVENT_TABLE()
26:
27: // コンストラクタ
28: WXLogSettingPanel::WXLogSettingPanel(wxWindow *parent)
29: : inherited(parent)
30: {
31: // エイリアスを持つオブジェクトだけ抜き出す
32: for (const auto obj : gMainApp.GetObjects()) {
33: if (obj->GetAliases().empty() == false) {
34: objs.emplace_back(obj);
35: }
36: }
37:
38: // ログ名でソート。
39: // ただし普通にソートすると "(BusErr)" とかの括弧付きがアルファベット
40: // より上に来てしまうが、ここではこれらは重要ではないので下にしたい。
41: std::sort(objs.begin(), objs.end(), [](Object *a, Object *b) {
42: std::string aname = a->GetName();
43: std::string bname = b->GetName();
44: if (aname[0] == '(') {
45: aname[0] = '{';
46: }
47: if (bname[0] == '(') {
48: bname[0] = '{';
49: }
50: return aname < bname;
51: });
52:
53: // 名前の最大長
54: maxnamelen = 0;
55: for (const auto obj : objs) {
56: maxnamelen = std::max(maxnamelen, (int)obj->GetName().length());
57: }
58:
59: FontChanged();
60: }
61:
62: // デストラクタ
63: WXLogSettingPanel::~WXLogSettingPanel()
64: {
65: }
66:
67: // 桁数 col の左端ピクセル座標を返す
68: inline int
69: WXLogSettingPanel::Col2PX(int col) const
70: {
71: return col * GetFontWidth() + Padding;
72: }
73:
74: // 行数 row の上端ピクセル座標を返す
75: inline int
76: WXLogSettingPanel::Row2PY(int row) const
77: {
78: // 縦はボタン描画の分少し広げてある
79: return row * (GetFontHeight() + 3) + Padding;
80: }
81:
82: // ピクセル x が含まれる桁を返す。
83: // py がパディング領域を指していると(テキストとしての)範囲外の値を返す。
84: inline int
85: WXLogSettingPanel::PX2Col(int px) const
86: {
87: return (px - Padding) / GetFontWidth();
88: }
89:
90: // ピクセル y が含まれる行を返す。
91: // py がパディング領域を指していると(テキストとしての)範囲外の値を返す。
92: inline int
93: WXLogSettingPanel::PY2Row(int py) const
94: {
95: return (py - Padding) / (GetFontHeight() + 3);
96: }
97:
98: // フォントサイズ変更
99: void
100: WXLogSettingPanel::FontChanged()
101: {
102: inherited::FontChanged();
103:
104: // 行数×桁数を基本とする
105: int col = maxnamelen + 10;
106: int row = objs.size() + 1;
107:
108: int width = Col2PX(col) + Padding;
109: int height = Row2PY(row) + Padding;
110: SetClientSize(width, height);
111: SetMinClientSize(wxSize(width, height));
112: }
113:
114: // ボタンのようなものを描画する。rect は外寸。
115: void
116: WXLogSettingPanel::DrawButton(const Rect& rect, bool button_pressed)
117: {
118: int l = rect.x;
119: int t = rect.y;
120: int r = rect.GetRight();
121: int b = rect.GetBottom();
122:
123: if (__predict_true(button_pressed == false)) {
124: // この場合外寸 7x7、内寸 3x3。
125: // 空白「 」のところが内側。
126: // 「・」は背景色で塗りつぶす (オンオフ逆側の陰影があるため)
127: //
128: // □□□□□□■ <- (1)
129: // □・・・・灰■ <- (2)
130: // □・ 灰■
131: // □・ 灰■
132: // □・ 灰■
133: // □灰灰灰灰灰■ <- (3)
134: // ■■■■■■■ <- (4)
135: // ^ ^ ^ ^
136: //(5)(6) (7)(8)
137:
138: bitmap.DrawLineH(UD_WHITE, l, t, r); // (1)
139: bitmap.DrawLineH(BGPANEL, l + 1, t + 1, r -1); // (2)
140: bitmap.DrawLineH(UD_GREY, l + 1, b - 1, r); // (3)
141: bitmap.DrawLineH(UD_BLACK, l, b, r + 1); // (4)
142: bitmap.DrawLineV(UD_WHITE, l, t + 1, b); // (5)
143: bitmap.DrawLineV(BGPANEL, l + 1, t + 2, b - 1); // (6)
144: bitmap.DrawLineV(UD_GREY, r - 1, t + 1, b - 1); // (7)
145: bitmap.DrawLineV(UD_BLACK, r, t, b); // (8)
146: } else {
147: // ■■■■■■□ <- (1)
148: // ■灰灰灰灰灰□ <- (2)
149: // ■灰 ・□
150: // ■灰 ・□
151: // ■灰 ・□
152: // ■灰・・・・□ <- (3)
153: // □□□□□□□ <- (4)
154: // ^ ^ ^ ^
155: //(5)(6) (7)(8)
156: bitmap.DrawLineH(UD_BLACK, l, t, r); // (1)
157: bitmap.DrawLineH(UD_GREY, l + 1, t + 1, r); // (2)
158: bitmap.DrawLineH(BGPANEL, l + 2, b - 1, r); // (3)
159: bitmap.DrawLineH(UD_WHITE, l, b, r + 1); // (4)
160: bitmap.DrawLineV(UD_BLACK, l, t + 1, b); // (5)
161: bitmap.DrawLineV(UD_GREY, l + 1, t + 1, b); // (6)
162: bitmap.DrawLineV(BGPANEL, r - 1, t + 2, b); // (7)
163: bitmap.DrawLineV(UD_WHITE, r, t, b); // (8)
164: }
165: }
166:
167: // 描画本体
168: void
169: WXLogSettingPanel::Draw()
170: {
171: const int width = GetFontWidth();
172: const int height = GetFontHeight();
173: int row;
174: int y;
175:
176: // ヘッダ
177: y = Row2PY(0);
178: DrawStringSJIS(Col2PX(0), y, "Name");
179: DrawStringSJIS(Col2PX(maxnamelen + 1), y, "LogLevel");
180:
181: row = 1;
182: for (const auto obj : objs) {
183: Rect rect;
184: Color c;
185:
186: y = Row2PY(row);
187:
188: DrawStringSJIS(Col2PX(0), y, obj->GetName().c_str());
189:
190: // 左ボタン (領域はテキスト2文字分)
191: int x = Col2PX(maxnamelen + 1);
192: if (obj->loglevel < 0) {
193: c = UD_GREY;
194: } else {
195: c = GetTextForeColor();
196: }
197: DrawStringSJIS(c, x + (width / 2), y, "<");
198: rect = Rect(x, y - 1, width * 2 + 2, height + 2);
199: DrawButton(rect, (row == -pressed));
200:
201: // 値
202: char lvstr[2];
203: if (__predict_false(obj->loglevel < 0)) {
204: lvstr[0] = '-';
205: } else if (__predict_true(obj->loglevel < 10)) {
206: lvstr[0] = obj->loglevel + '0';
207: } else {
208: lvstr[0] = '?';
209: }
210: lvstr[1] = '\0';
211: DrawStringSJIS(Col2PX(maxnamelen + 5), y, lvstr);
212:
213: // 値の枠
214: x = Col2PX(maxnamelen + 4);
215: rect = Rect(x, y - 1, width * 3, height + 1);
216: int l = rect.x;
217: int t = rect.y;
218: int r = rect.GetRight();
219: int b = rect.GetBottom();
220: bitmap.DrawLineH(UD_GREY, l, t, r);
221: bitmap.DrawLineH(UD_WHITE, l, b, r + 1);
222: bitmap.DrawLineV(UD_GREY, l, t + 1, b);
223: bitmap.DrawLineV(UD_WHITE, r, t, b);
224:
225: // 右ボタン
226: x = Col2PX(maxnamelen + 8);
227: if (obj->loglevel >= 9) {
228: c = UD_GREY;
229: } else {
230: c = GetTextForeColor();
231: }
232: DrawStringSJIS(c, x + (width / 2), y, ">");
233: rect = Rect(x, y - 1, width * 2 + 2, height + 2);
234: DrawButton(rect, (row == pressed));
235:
236: row++;
237: }
238: }
239:
240: // 左クリック (Down) イベント
241: void
242: WXLogSettingPanel::OnLeftDown(wxMouseEvent& event)
243: {
244: const wxPoint& pos = event.GetPosition();
245: int x = PX2Col(pos.x);
246: int y = PY2Row(pos.y);
247:
248: // 上下のパディング領域とヘッダ行を先に除いておく
249: // (左右は影響しないので放置でいい)
250: if (y < 1 || y >= objs.size()) {
251: return;
252: }
253:
254: Object *obj = objs[y - 1];
255: int level = obj->loglevel;
256:
257: // クリックされた場所がボタンの位置か
258: if (maxnamelen + 1 <= x && x <= maxnamelen + 2) {
259: if (level > -1) {
260: level--;
261: }
262: // "<" ボタンは負数で覚えておく (0 はないので大丈夫)
263: pressed = -y;
264: } else if (maxnamelen + 8 <= x) {
265: // 今の所上限は未定だけど、表示上の都合で一桁にしておくか
266: if (level < 9) {
267: level++;
268: }
269: // ">" ボタンは正数で覚えておく
270: pressed = y;
271: }
272:
273: if (level != obj->loglevel) {
274: obj->SetLogLevel(level);
275: }
276:
277: Refresh();
278: }
279:
280: // 左クリック (Up) イベント
281: void
282: WXLogSettingPanel::OnLeftUp(wxMouseEvent& event)
283: {
284: // クリックを上げた場所は問わない
285: pressed = 0;
286: Refresh();
287: }
288:
289:
290: //
291: // ウィンドウ
292: //
293:
294: // コンストラクタ
295: WXLogSettingWindow::WXLogSettingWindow(wxWindow *parent)
296: : inherited(parent, wxID_ANY, _("Log Level Setting"))
297: {
298: panel = new WXLogSettingPanel(this);
299:
300: DoSize();
301: }
302:
303: // デストラクタ
304: WXLogSettingWindow::~WXLogSettingWindow()
305: {
306: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.