|
|
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.