Annotation of nono/wx/wxstatuspanel.cpp, revision 1.1.1.1

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2021 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: // ステータスパネル
                      8: //
                      9: // 描画領域に対してフォントの開始位置は外枠から +4、内枠からなら +2。
                     10: // 横も同様。
                     11: //
                     12: // +0 ------ 外枠
                     13: // +1        アキ
                     14: // +2  +---- 内枠
                     15: // +3  |     アキ
                     16: // +4  | ここからフォント
                     17: 
                     18: #include "wxstatuspanel.h"
                     19: #include "wxcolor.h"
                     20: #include "wxmainview.h"
                     21: #include "bitrev.h"
                     22: #include "netdriver.h"
                     23: #include "scheduler.h"
                     24: #include "spc.h"
                     25: 
                     26: WXStatusPanel *gStatusPanel;
                     27: 
                     28: wxBEGIN_EVENT_TABLE(WXStatusPanel, inherited)
                     29:        EVT_CREATE(WXStatusPanel::OnCreate)
                     30:        EVT_CLOSE(WXStatusPanel::OnClose)
                     31:        EVT_SHOW(WXStatusPanel::OnShow)
                     32:        EVT_SIZE(WXStatusPanel::OnSize)
                     33:        EVT_TIMER(wxID_ANY, WXStatusPanel::OnTimer)
                     34:        EVT_PAINT(WXStatusPanel::OnPaint)
                     35:        EVT_LEFT_DCLICK(WXStatusPanel::OnLeftDClick)
                     36: wxEND_EVENT_TABLE()
                     37: 
                     38: // ステータスパネルの更新頻度 [Hz]
                     39: static constexpr uint FPS = 10;
                     40: 
                     41: // style フラグ
                     42: // デフォルトは wxTAB_TRAVERSAL だがこれを外すので分かりづらい字面になる
                     43: static const long STATUS_PANEL_STYLE = 0;
                     44: 
                     45: // コンストラクタ
                     46: WXStatusPanel::WXStatusPanel(wxWindow *parent)
                     47:        : inherited(parent, STATUS_PANEL_STYLE)
                     48: {
                     49:        timer.SetOwner(this);
                     50: 
                     51:        // インジケータ用のパラメータを用意。
                     52:        InitIndicators();
                     53: 
                     54:        DoSize();
                     55: 
                     56:        // メインビューにイベントを接続したいがこの時点ではまだ gMainView が
                     57:        // ないので OnCreate イベントで処理する。
                     58:        POST_CREATE();
                     59: }
                     60: 
                     61: // デストラクタ
                     62: WXStatusPanel::~WXStatusPanel()
                     63: {
                     64: }
                     65: 
                     66: // ウィンドウ作成イベント
                     67: void
                     68: WXStatusPanel::OnCreate(wxCommandEvent& event)
                     69: {
                     70:        // キー入力イベントをメインビューに転送。
                     71:        // このパネルへのキー入力は不要なのと、メインウィンドウ内のコントロール
                     72:        // フォーカスがこのステータスパネルとメインビューのどっちにあるかは
                     73:        // 分かりづらくて、こっちがフォーカス持ってしまうと (というか起動後は
                     74:        // こっちにある) VM にキー入力が出来ずに焦ることになるので、ここへの
                     75:        // キー入力イベントは全部メインビューに飛ばす。
                     76:        Connect(wxEVT_KEY_UP, wxKeyEventHandler(WXMainView::OnKeyUp), NULL,
                     77:                gMainView);
                     78:        Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(WXMainView::OnKeyDown), NULL,
                     79:                gMainView);
                     80: }
                     81: 
                     82: // クローズイベント
                     83: void
                     84: WXStatusPanel::OnClose(wxCloseEvent& event)
                     85: {
                     86:        // クローズする前に更新を止める。
                     87:        timer.Stop();
                     88: }
                     89: 
                     90: // フォントサイズ変更 (外部インタフェース)
                     91: void
                     92: WXStatusPanel::SetFontSize(FontId new_fontid)
                     93: {
                     94:        // 同じなら何もしない
                     95:        if (fontid == new_fontid) {
                     96:                return;
                     97:        }
                     98: 
                     99:        // フォントを変更
                    100:        UpdateFont(new_fontid);
                    101: 
                    102:        // サイズ変更処理
                    103:        DoSize();
                    104: }
                    105: 
                    106: // 表示/非表示変更イベント
                    107: // new した時は (デフォルトで表示状態なのでか状態に変更がないという扱いの
                    108: // ようで) イベントは飛んでこない。同様に new 直後に Show() を明示発行しても
                    109: // 状態に変更がないためイベントは飛んでこない。
                    110: // new 直後に Hide() すればイベントは飛んでくる。という動作をするようだ。
                    111: // そのため WXMainFrame 側で生成後に Show/Hide を起こしている。
                    112: void
                    113: WXStatusPanel::OnShow(wxShowEvent& event)
                    114: {
                    115:        if (event.IsShown()) {
                    116:                // 非表示→表示
                    117: 
                    118:                // 表示開始前に一度情報を取得
                    119:                UpdateStat();
                    120: 
                    121:                timer.Start(1000 / FPS);
                    122:        } else {
                    123:                // 表示→非表示
                    124: 
                    125:                timer.Stop();
                    126:        }
                    127: }
                    128: 
                    129: // サイズ変更処理
                    130: // サイズを変更したい時に呼ぶ (サイズが変更されたからではない)。
                    131: // ここではサイズは fontsize にのみ依存しているので、フォントサイズが
                    132: // 変化/確定した時に呼び出すこと。
                    133: void
                    134: WXStatusPanel::DoSize()
                    135: {
                    136:        assert(fontid != FontId::None);
                    137: 
                    138:        // ここで高速モードアイコンを作る、あるいは変更する。
                    139:        // どこでやるか悩ましいけど、ここがフォントサイズが変わった時と
                    140:        // 起動時の他のイベントより先に呼ばれるので。
                    141:        UpdateFFMark();
                    142: 
                    143:        // コントロールの大きさを変更
                    144:        wxSize size(wxDefaultCoord, font_height + 8);
                    145:        SetClientSize(size);
                    146:        SetMinClientSize(size);
                    147: }
                    148: 
                    149: // サイズ変更イベント
                    150: void
                    151: WXStatusPanel::OnSize(wxSizeEvent& event)
                    152: {
                    153:        // Mac ではウィンドウ作成時に 0 以下の値が来ることがある
                    154:        // GTK では 1 で来ることがある
                    155:        const wxSize& size = event.GetSize();
                    156:        if (size.x <= 1 || size.y <= 1) {
                    157:                return;
                    158:        }
                    159: 
                    160:        // ビットマップ作成
                    161:        bitmap.Create(size.x, size.y);
                    162: 
                    163:        LayoutIndicators();
                    164: 
                    165:        // 再描画を指示
                    166:        Refresh();
                    167: }
                    168: 
                    169: // タイマーイベント
                    170: void
                    171: WXStatusPanel::OnTimer(wxTimerEvent& event)
                    172: {
                    173:        if (UpdateStat()) {
                    174:                Refresh();
                    175:        }
                    176: }
                    177: 
                    178: // 状態をチェック。
                    179: // 前回値からどれかでも変更があれば true を返す。
                    180: bool
                    181: WXStatusPanel::UpdateStat()
                    182: {
                    183:        bool updated = false;
                    184: 
                    185:        // 電源オンか
                    186:        ispower = gScheduler->IsPower();
                    187:        if (last_ispower != ispower) {
                    188:                last_ispower = ispower;
                    189:                updated = true;
                    190:        }
                    191: 
                    192:        // パフォーマンスカウンタ
                    193:        perf_mode = gScheduler->GetRunMode();
                    194:        if (last_perf_mode != perf_mode) {
                    195:                last_perf_mode = perf_mode;
                    196:                updated = true;
                    197:        }
                    198:        perf_rate = gScheduler->GetPerfCounter();
                    199:        if (last_perf_rate != perf_rate) {
                    200:                last_perf_rate = perf_rate;
                    201:                updated = true;
                    202:        }
                    203: 
                    204:        // FD
                    205: 
                    206:        // SCSI アクセス
                    207:        scsi_bsy = scsibus->GetBSY();
                    208:        if (scsi_bsy != last_scsi_bsy) {
                    209:                last_scsi_bsy = scsi_bsy;
                    210:                updated = true;
                    211:        }
                    212: 
                    213:        // ネットワーク
                    214: 
                    215:        // 電源
                    216: 
                    217:        return updated;
                    218: }
                    219: 
                    220: // 描画イベント
                    221: void
                    222: WXStatusPanel::OnPaint(wxPaintEvent& event)
                    223: {
                    224:        // メモリ DC に描画
                    225:        wxMemoryDC memDC;
                    226:        memDC.SelectObject(bitmap);
                    227:        Draw(memDC);
                    228: 
                    229:        // 実画面 DC にコピー
                    230:        wxPaintDC dstDC(this);
                    231:        wxSize size = bitmap.GetSize();
                    232:        dstDC.Blit(0, 0, size.x, size.y, &memDC, 0, 0);
                    233: }
                    234: 
                    235: // 描画本体
                    236: void
                    237: WXStatusPanel::Draw(wxDC& dc)
                    238: {
                    239:        std::string text;
                    240: 
                    241:        // 背景はいつものグレー。
                    242:        wxSize size = GetSize();
                    243:        dc.SetPen(wxPen(BGPANEL));
                    244:        dc.SetBrush(wxBrush(BGPANEL));
                    245:        dc.DrawRectangle(wxPoint(0, 0), size);
                    246: 
                    247:        // なんとなく見栄えのため上下に薄い線を引く。
                    248:        // 四方を線で囲むとオーバーレイウィンドウのように見えるので上下だけ。
                    249:        dc.SetPen(wxPen(UD_GREY));
                    250:        dc.DrawLine(0, 0, size.x - 1, 0);
                    251:        dc.DrawLine(0, size.y - 1, size.x - 1, size.y - 1);
                    252: 
                    253:        // 各インジケータを描画
                    254:        for (auto& ind : indicators) {
                    255:                (this->*(ind.draw))(dc, ind);
                    256:        }
                    257: }
                    258: 
                    259: // インジケータの初期化
                    260: void
                    261: WXStatusPanel::InitIndicators()
                    262: {
                    263:        // パフォーマンスカウンタ
                    264:        Indicator perf(">>>9999%", &WXStatusPanel::DrawPerf);
                    265:        perf.dclick = &WXStatusPanel::DClickPerf;
                    266:        indicators.emplace_back(perf);
                    267: 
                    268:        // FD
                    269: 
                    270:        // SCSI
                    271:        // SPC の接続済みデバイスリストから取得。
                    272:        // (ホストアダプタ2つ目のことは考えてない)
                    273:        const std::vector<SCSIDevice *>& conn = gSPC->GetConnectedDevices();
                    274:        for (const auto& dev : conn) {
                    275:                int id = dev->GetMyID();
                    276:                SCSI::DevType devtype = dev->GetDevType();
                    277: 
                    278:                std::string disp;
                    279:                switch (devtype) {
                    280:                 case SCSI::DevType::Initiator:
                    281:                        continue;
                    282:                 case SCSI::DevType::HD:
                    283:                        disp = "HD";
                    284:                        break;
                    285:                 default:
                    286:                        disp = "??";
                    287:                        break;
                    288:                }
                    289:                disp += string_format("%d", id);
                    290: 
                    291:                indicators.emplace_back(disp, &WXStatusPanel::DrawSCSI, id);
                    292:        }
                    293:        // BSY 取得用
                    294:        scsibus = gSPC->GetSCSIBus();
                    295: 
                    296:        // ネットワーク
                    297: #if 0 // XXX まだアクセスランプどうするか要調査
                    298:        if (gNetDriver->IsOpen()) {
                    299:                net_ok = true;
                    300:        } else {
                    301:                net_ok = false;
                    302:        }
                    303:        indicators.emplace_back("LAN", &WXStatusPanel::DrawNet);
                    304: #endif
                    305: 
                    306:        // 電源 LED。点灯ロジックが分からないのでハリボテ。
                    307:        // ロジックが分かった時のために一応 3 文字にしておく。
                    308:        indicators.emplace_back("PWR", &WXStatusPanel::DrawPower);
                    309: }
                    310: 
                    311: // インジケータのレイアウト
                    312: void
                    313: WXStatusPanel::LayoutIndicators()
                    314: {
                    315:        int x;
                    316:        int y;
                    317:        int w;
                    318:        int h;
                    319: 
                    320:        // まずは前から順に列挙して必要な幅を積算していく
                    321:        x = 0;
                    322:        for (auto& ind : indicators) {
                    323:                // 前の枠とは1つ開ける
                    324:                if (x != 0) {
                    325:                        x += 1;
                    326:                }
                    327: 
                    328:                // 上の枠はキャンバス上端から2px
                    329:                y = 2;
                    330:                // 4 は、左右の外枠(1*2) と 枠と文字の間(1*2)
                    331:                w = ind.text.length() * font_width + 2 + 2;
                    332:                // そこから上下の外枠と枠と文字の間
                    333:                h = font_height + 2 + 2;
                    334: 
                    335:                ind.rect = wxRect(x, y, w, h);
                    336:                x += w;
                    337:        }
                    338: 
                    339:        // 全員を一旦右寄せ
                    340:        wxSize sz = GetClientSize();
                    341:        int offsetx = sz.x - x;
                    342:        for (auto& ind : indicators) {
                    343:                ind.rect.Offset(offsetx, 0);
                    344:        }
                    345: 
                    346:        // そのうちパフォーマンスカウンタだけ中央寄せまで戻す
                    347:        if (indicators.size() > 0) {
                    348:                auto& p = indicators.front();
                    349:                x = (sz.x / 2) - (p.rect.GetWidth() / 2);
                    350:                if (p.rect.GetX() > x) {
                    351:                        p.rect.SetX(x);
                    352:                }
                    353:        }
                    354: }
                    355: 
                    356: // パフォーマンスカウンタ
                    357: void
                    358: WXStatusPanel::DrawPerf(wxDC& dc, const Indicator& ind)
                    359: {
                    360:        const wxRect& rect = ind.rect;
                    361: 
                    362:        // 枠
                    363:        dc.SetPen(wxPen(UD_GREY));
                    364:        dc.SetBrush(wxBrush(BGPANEL));
                    365:        dc.DrawRectangle(rect);
                    366: 
                    367:        // 電源オフならここまで
                    368:        if (ispower == false) {
                    369:                return;
                    370:        }
                    371: 
                    372:        // 高速モードアイコン
                    373:        // UI による高速モード指示なら >> (2つ)
                    374:        // そのうち実際に高速動作なら  >>> (3つ)
                    375:        if ((perf_mode & Scheduler::SCHED_SYNC) == 0) {
                    376:                SetTextForeColor(UD_RED);
                    377:                DrawBitmap(dc, rect.x + 2, rect.y + 2, *ffmark);
                    378:                DrawBitmap(dc, rect.x + 2 + font_width, rect.y + 2, *ffmark);
                    379:                if (perf_mode == 0) {
                    380:                        DrawBitmap(dc, rect.x + 2 + font_width * 2, rect.y + 2, *ffmark);
                    381:                }
                    382:                SetTextForeColor(*wxBLACK);
                    383:        }
                    384: 
                    385:        // パフォーマンス表示
                    386:        std::string text = string_format("%4d%%", perf_rate);
                    387:        DrawStringSJIS(dc, rect.x + 2 + font_width * 3, rect.y + 2, text.c_str());
                    388: }
                    389: 
                    390: // SCSI デバイス側のアクセスランプ
                    391: // 本体ではなく各 SCSI デバイス側 (外付け HDD の前面とか) にあるやつ。
                    392: void
                    393: WXStatusPanel::DrawSCSI(wxDC& dc, const Indicator& ind)
                    394: {
                    395:        wxColour bg;
                    396: 
                    397:        if ((scsi_bsy & (1U << ind.userdata)) != 0) {
                    398:                bg = UD_RED;
                    399:        } else {
                    400:                bg = BGPANEL;
                    401:        }
                    402: 
                    403:        DrawTextLED(dc, ind, *wxBLACK, bg);
                    404: }
                    405: 
                    406: // ネットワーク(LAN)
                    407: void
                    408: WXStatusPanel::DrawNet(wxDC& dc, const Indicator& ind)
                    409: {
                    410:        wxColour fg;
                    411:        wxColour bg = BGPANEL;
                    412: 
                    413:        if (net_ok) {
                    414:                fg = *wxBLACK;
                    415:        } else {
                    416:                fg = UD_GREY;
                    417:        }
                    418: 
                    419:        DrawTextLED(dc, ind, fg, bg);
                    420: }
                    421: 
                    422: // 電源LED?
                    423: void
                    424: WXStatusPanel::DrawPower(wxDC& dc, const Indicator& ind)
                    425: {
                    426:        DrawTextLED(dc, ind, *wxBLACK, UD_YELLOW_GREEN);
                    427: }
                    428: 
                    429: // 共通の描画処理。
                    430: // ind.text を前景色 fg、背景色 bg で描画するだけの場合。
                    431: void
                    432: WXStatusPanel::DrawTextLED(wxDC& dc, const Indicator& ind,
                    433:        const wxColour& fg, const wxColour& bg)
                    434: {
                    435:        const wxRect& rect = ind.rect;
                    436: 
                    437:        // 枠
                    438:        dc.SetPen(wxPen(UD_GREY));
                    439:        dc.SetBrush(wxBrush(bg));
                    440:        dc.DrawRectangle(rect);
                    441: 
                    442:        SetTextColor(fg, bg);
                    443:        DrawStringSJIS(dc, rect.x + 2, rect.y + 2, ind.text.c_str());
                    444:        ResetTextColor();
                    445: }
                    446: 
                    447: // 左ダブルクリックイベント
                    448: void
                    449: WXStatusPanel::OnLeftDClick(wxMouseEvent& event)
                    450: {
                    451:        const wxPoint& pt = event.GetPosition();
                    452: 
                    453:        for (auto& ind : indicators) {
                    454:                // dclick を処理できる枠内なら
                    455:                if (ind.rect.Contains(pt) && ind.dclick != NULL) {
                    456:                        (this->*(ind.dclick))(ind);
                    457:                        break;
                    458:                }
                    459:        }
                    460: }
                    461: 
                    462: // パフォーマンスカウンタ枠へのダブルクリック
                    463: void
                    464: WXStatusPanel::DClickPerf(const Indicator& ind)
                    465: {
                    466:        // モードを切り替える
                    467:        gScheduler->SetFullSpeed(!gScheduler->GetFullSpeed());
                    468: }
                    469: 
                    470: // 高速モードアイコンの三角一個分、半角文字と同じ大きさ。
                    471: // XBM データは左右鏡像(反転前に左詰め)で保持する。
                    472: static constexpr uint8 FFMark12[] = {
                    473:        _rev8(0b000000'00),             // 0
                    474:        _rev8(0b100000'00),             // 1
                    475:        _rev8(0b110000'00),             // 2
                    476:        _rev8(0b111000'00),             // 3
                    477:        _rev8(0b111100'00),             // 4
                    478:        _rev8(0b111110'00),             // 5
                    479:        _rev8(0b111111'00),             // 6
                    480:        _rev8(0b111110'00),             // 7
                    481:        _rev8(0b111100'00),             // 8
                    482:        _rev8(0b111000'00),             // 9
                    483:        _rev8(0b110000'00),             // a
                    484:        _rev8(0b100000'00),             // b
                    485: };
                    486: static constexpr uint8 FFMark16[] = {
                    487:        _rev8(0b00000000),              // 0
                    488:        _rev8(0b10000000),              // 1
                    489:        _rev8(0b11000000),              // 2
                    490:        _rev8(0b11100000),              // 3
                    491:        _rev8(0b11110000),              // 4
                    492:        _rev8(0b11111000),              // 5
                    493:        _rev8(0b11111100),              // 6
                    494:        _rev8(0b11111110),              // 7
                    495:        _rev8(0b11111111),              // 8
                    496:        _rev8(0b11111110),              // 9
                    497:        _rev8(0b11111100),              // a
                    498:        _rev8(0b11111000),              // b
                    499:        _rev8(0b11110000),              // c
                    500:        _rev8(0b11100000),              // d
                    501:        _rev8(0b11000000),              // e
                    502:        _rev8(0b10000000),              // f
                    503: };
                    504: 
                    505: // 高速モードアイコン(の1文字分)を現在のフォントサイズに合わせて作り直す
                    506: void
                    507: WXStatusPanel::UpdateFFMark()
                    508: {
                    509:        const uint8 *xbm;
                    510: 
                    511:        switch (fontid) {
                    512:         case FontId::_6x12:
                    513:                xbm = FFMark12;
                    514:                break;
                    515:         case FontId::_8x16:
                    516:                xbm = FFMark16;
                    517:                break;
                    518:         default:
                    519:                assert(false);
                    520:        }
                    521:        ffmark.reset(new wxBitmap((const char *)xbm, font_width, font_height, 1));
                    522: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.