Annotation of nono/wx/wxstatuspanel.cpp, revision 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.