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

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2021 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
1.1.1.4   root        7: //
1.1       root        8: // ステータスパネル
                      9: //
1.1.1.4   root       10: 
1.1       root       11: // 描画領域に対してフォントの開始位置は外枠から +4、内枠からなら +2。
                     12: // 横も同様。
                     13: //
                     14: // +0 ------ 外枠
                     15: // +1        アキ
                     16: // +2  +---- 内枠
                     17: // +3  |     アキ
                     18: // +4  | ここからフォント
                     19: 
                     20: #include "wxstatuspanel.h"
1.1.1.4   root       21: #include "fontmanager.h"
1.1       root       22: #include "wxcolor.h"
1.1.1.3   root       23: #include "wxmainframe.h"
1.1       root       24: #include "wxmainview.h"
1.1.1.3   root       25: #include "wxuimessage.h"
1.1.1.5   root       26: #include "fdc.h"
1.1.1.4   root       27: #include "hostnet.h"
1.1.1.6   root       28: #include "newsctlr.h"
1.1.1.4   root       29: #include "power.h"
1.1       root       30: #include "spc.h"
1.1.1.6   root       31: #include "syncer.h"
1.1.1.8 ! root       32: #include "virtio_block.h"
1.1       root       33: 
                     34: wxBEGIN_EVENT_TABLE(WXStatusPanel, inherited)
                     35:        EVT_CLOSE(WXStatusPanel::OnClose)
                     36:        EVT_SHOW(WXStatusPanel::OnShow)
                     37:        EVT_SIZE(WXStatusPanel::OnSize)
                     38:        EVT_TIMER(wxID_ANY, WXStatusPanel::OnTimer)
                     39:        EVT_LEFT_DCLICK(WXStatusPanel::OnLeftDClick)
1.1.1.3   root       40:        EVT_CONTEXT_MENU(WXStatusPanel::OnContextMenu)
1.1       root       41: wxEND_EVENT_TABLE()
                     42: 
                     43: // ステータスパネルの更新頻度 [Hz]
                     44: static constexpr uint FPS = 10;
                     45: 
                     46: // style フラグ
                     47: // デフォルトは wxTAB_TRAVERSAL だがこれを外すので分かりづらい字面になる
                     48: static const long STATUS_PANEL_STYLE = 0;
                     49: 
                     50: // コンストラクタ
                     51: WXStatusPanel::WXStatusPanel(wxWindow *parent)
1.1.1.6   root       52:        : inherited(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
                     53:                STATUS_PANEL_STYLE)
1.1       root       54: {
                     55:        timer.SetOwner(this);
                     56: 
1.1.1.7   root       57:        power = GetPowerDevice();
                     58:        syncer = GetSyncer();
                     59: 
1.1       root       60:        // インジケータ用のパラメータを用意。
                     61:        InitIndicators();
                     62: 
1.1.1.4   root       63:        FontChanged();
1.1       root       64: 
                     65:        // キー入力イベントをメインビューに転送。
                     66:        // このパネルへのキー入力は不要なのと、メインウィンドウ内のコントロール
                     67:        // フォーカスがこのステータスパネルとメインビューのどっちにあるかは
                     68:        // 分かりづらくて、こっちがフォーカス持ってしまうと (というか起動後は
                     69:        // こっちにある) VM にキー入力が出来ずに焦ることになるので、ここへの
                     70:        // キー入力イベントは全部メインビューに飛ばす。
1.1.1.6   root       71:        auto mainframe = dynamic_cast<WXMainFrame*>(GetParent());
                     72:        auto mainview = mainframe->GetMainView();
1.1       root       73:        Connect(wxEVT_KEY_UP, wxKeyEventHandler(WXMainView::OnKeyUp), NULL,
1.1.1.6   root       74:                mainview);
1.1       root       75:        Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(WXMainView::OnKeyDown), NULL,
1.1.1.6   root       76:                mainview);
1.1.1.3   root       77: 
1.1.1.5   root       78:        // VM からの通知を受け取る
1.1.1.3   root       79:        WXUIMessage::Connect(UIMessage::SCSI_MEDIA_CHANGE, this,
                     80:                wxCommandEventHandler(WXStatusPanel::OnSCSIMediaChanged));
1.1.1.5   root       81:        WXUIMessage::Connect(UIMessage::FDD_MEDIA_CHANGE, this,
                     82:                wxCommandEventHandler(WXStatusPanel::OnFDDMediaChanged));
                     83:        WXUIMessage::Connect(UIMessage::LED, this,
                     84:                wxCommandEventHandler(WXStatusPanel::OnLEDChanged));
1.1       root       85: }
                     86: 
1.1.1.2   root       87: // デストラクタ
                     88: WXStatusPanel::~WXStatusPanel()
                     89: {
1.1.1.4   root       90:        while (indicators.empty() == false) {
                     91:                Indicator *ind = indicators.back();
                     92:                indicators.pop_back();
                     93:                delete ind;
                     94:        }
1.1.1.5   root       95: 
1.1.1.6   root       96:        WXUIMessage::Disconnect(UIMessage::SCSI_MEDIA_CHANGE, this,
1.1.1.4   root       97:                wxCommandEventHandler(WXStatusPanel::OnSCSIMediaChanged));
1.1.1.6   root       98:        WXUIMessage::Disconnect(UIMessage::FDD_MEDIA_CHANGE, this,
1.1.1.5   root       99:                wxCommandEventHandler(WXStatusPanel::OnFDDMediaChanged));
1.1.1.6   root      100:        WXUIMessage::Disconnect(UIMessage::LED, this,
1.1.1.5   root      101:                wxCommandEventHandler(WXStatusPanel::OnLEDChanged));
1.1.1.2   root      102: }
                    103: 
1.1       root      104: // クローズイベント
                    105: void
                    106: WXStatusPanel::OnClose(wxCloseEvent& event)
                    107: {
                    108:        // クローズする前に更新を止める。
                    109:        timer.Stop();
                    110: }
                    111: 
                    112: // 表示/非表示変更イベント
                    113: // new した時は (デフォルトで表示状態なのでか状態に変更がないという扱いの
                    114: // ようで) イベントは飛んでこない。同様に new 直後に Show() を明示発行しても
                    115: // 状態に変更がないためイベントは飛んでこない。
                    116: // new 直後に Hide() すればイベントは飛んでくる。という動作をするようだ。
                    117: // そのため WXMainFrame 側で生成後に Show/Hide を起こしている。
                    118: void
                    119: WXStatusPanel::OnShow(wxShowEvent& event)
                    120: {
                    121:        if (event.IsShown()) {
                    122:                // 非表示→表示
                    123: 
                    124:                // 表示開始前に一度情報を取得
                    125:                UpdateStat();
                    126: 
                    127:                timer.Start(1000 / FPS);
                    128:        } else {
                    129:                // 表示→非表示
                    130: 
                    131:                timer.Stop();
                    132:        }
                    133: }
                    134: 
1.1.1.4   root      135: // フォントサイズ変更
1.1       root      136: void
1.1.1.4   root      137: WXStatusPanel::FontChanged()
1.1       root      138: {
1.1.1.4   root      139:        inherited::FontChanged();
                    140: 
1.1.1.6   root      141:        // アクセスマークをサイズに応じて作り直す
                    142:        const uint8 *src;
                    143:        switch (font_height) {
                    144:         case 12:
                    145:                src = AccessMark12;
                    146:                break;
                    147:         case 16:
                    148:                src = AccessMark16;
                    149:                break;
                    150:         case 24:
                    151:                src = AccessMark24;
                    152:                break;
                    153:         default:
                    154:                PANIC("Unexpected font_height=%d", font_height);
                    155:        }
                    156:        accmark.reset(new BitmapI8(src, font_height, font_height));
                    157: 
1.1.1.4   root      158:        // インジケータを再レイアウト
                    159:        LayoutIndicators();
1.1       root      160: 
                    161:        // コントロールの大きさを変更
1.1.1.4   root      162:        wxSize size = GetClientSize();
                    163:        size.y = font_height + 8;
1.1       root      164:        SetClientSize(size);
                    165: }
                    166: 
                    167: // サイズ変更イベント
                    168: void
                    169: WXStatusPanel::OnSize(wxSizeEvent& event)
                    170: {
1.1.1.5   root      171:        // Mac ではウィンドウ作成時に 0 以下の値が来ることがある。
                    172:        // GTK では 1 で来ることがある。
1.1       root      173:        const wxSize& size = event.GetSize();
                    174:        if (size.x <= 1 || size.y <= 1) {
                    175:                return;
                    176:        }
                    177: 
1.1.1.4   root      178:        // 親クラス
                    179:        inherited::OnSize(event);
1.1       root      180: 
                    181:        LayoutIndicators();
                    182: 
                    183:        // 再描画を指示
                    184:        Refresh();
                    185: }
                    186: 
                    187: // タイマーイベント
                    188: void
                    189: WXStatusPanel::OnTimer(wxTimerEvent& event)
                    190: {
                    191:        if (UpdateStat()) {
                    192:                Refresh();
                    193:        }
                    194: }
                    195: 
1.1.1.7   root      196: // store に value を代入。更新されていれば updated を立てる。
                    197: // value は引数に渡す時に一度だけ評価される。
                    198: #define MODIFY(store, value_)  ({      \
                    199:        bool mod_;      \
                    200:        decltype(value_) value = value_;        \
                    201:        if (store != value)     { \
                    202:                store = value;  \
                    203:                mod_ = true;    \
                    204:        } else {        \
                    205:                mod_ = false;   \
                    206:        }       \
                    207:        mod_;   /* return value */      \
                    208: })
                    209: 
                    210: //
                    211: // インジケータ用の情報
                    212: //
                    213: class Status
                    214: {
                    215:  public:
                    216:        virtual ~Status() = default;
                    217: 
                    218:        // 情報取得メソッド
                    219:        virtual bool Poll() = 0;
                    220: };
                    221: 
                    222: //
                    223: // SCSI 情報
                    224: //
                    225: class StatusSCSI : public Status
                    226: {
                    227:  public:
                    228:        StatusSCSI(SCSIBus *scsibus_) {
                    229:                scsibus = scsibus_;
                    230:        }
                    231:        virtual ~StatusSCSI() override = default;
                    232: 
                    233:        bool Poll() override {
                    234:                bool mod = false;
                    235:                mod |= MODIFY(bsy, scsibus->GetBSY());
                    236:                // 転送フェーズで DataOut の時だけ書き込みとみなす
                    237:                bool out = (scsibus->GetPhase() == SCSI::Phase::Transfer)
                    238:                        && (scsibus->GetXfer()  == SCSI::XferPhase::DataOut);
                    239:                mod |= MODIFY(dataout, out);
                    240:                return mod;
                    241:        }
                    242: 
                    243:        uint8 bsy {};           // BSY (ID0-7)
                    244:        bool dataout {};        // DataOut フェーズなら true
                    245: 
                    246:  private:
                    247:        SCSIBus *scsibus {};
                    248: };
                    249: 
                    250: //
1.1.1.8 ! root      251: // VirtIOBlock 情報
        !           252: //
        !           253: class StatusVBlk : public Status
        !           254: {
        !           255:  public:
        !           256:        StatusVBlk(VirtIOBlockDevice *dev_) {
        !           257:                dev = dev_;
        !           258:        }
        !           259:        virtual ~StatusVBlk() override = default;
        !           260: 
        !           261:        bool Poll() override {
        !           262:                bool rmod = MODIFY(access_read,  dev->GetAccessRead());
        !           263:                bool wmod = MODIFY(access_write, dev->GetAccessWrite());
        !           264: 
        !           265:                bool mod = false;
        !           266:                mod |= MODIFY(read_active, rmod);
        !           267:                mod |= MODIFY(write_active, wmod);
        !           268:                return mod;
        !           269:        }
        !           270: 
        !           271:        // アクセス状況
        !           272:        uint32 access_read {};
        !           273:        uint32 access_write {};
        !           274:        bool read_active {};
        !           275:        bool write_active {};
        !           276: 
        !           277:  private:
        !           278:        VirtIOBlockDevice *dev {};
        !           279: };
        !           280: 
        !           281: //
1.1.1.7   root      282: // ネットワーク情報
                    283: //
                    284: class StatusNet : public Status
                    285: {
                    286:  public:
                    287:        StatusNet(HostNetDevice *hostnet_) {
                    288:                hostnet = hostnet_;
                    289:        }
                    290:        virtual ~StatusNet() override = default;
                    291: 
                    292:        bool Poll() override {
                    293:                // パケット数が変化したとき、および
                    294:                // その変化を監視しているアクティブ状態が変化したときに
                    295:                // 変更があったとしたいので二重になっている。
                    296:                bool tx_mod = MODIFY(tx_pkts, hostnet->GetTXPkts());
                    297:                bool rx_mod = MODIFY(rx_pkts, hostnet->GetRXPkts());
                    298: 
                    299:                bool mod = false;
                    300:                mod |= MODIFY(tx_active, tx_mod);
                    301:                mod |= MODIFY(rx_active, rx_mod);
                    302:                return mod;
                    303:        }
                    304: 
                    305:        bool enable {};
                    306:        uint64 tx_pkts {};
                    307:        uint64 rx_pkts {};
                    308:        bool tx_active {};
                    309:        bool rx_active {};
                    310: 
                    311:  private:
                    312:        HostNetDevice *hostnet {};
                    313: };
                    314: 
                    315: //
                    316: // FDD 情報
                    317: //
                    318: class StatusFDD : public Status
                    319: {
                    320:  public:
                    321:        StatusFDD(FDDDevice *fdd_) {
                    322:                fdd = fdd_;
                    323:        }
                    324:        virtual ~StatusFDD() override = default;
                    325: 
                    326:        bool Poll() override {
                    327:                bool mod = false;
                    328:                mod |= MODIFY(access_led, fdd->GetAccessLED());
                    329:                mod |= MODIFY(eject_led,  fdd->GetEjectLED());
                    330:                return mod;
                    331:        }
                    332: 
                    333:        FDDDevice::LED access_led {};   // アクセス LED の状態
                    334:        bool eject_led {};                              // イジェクト LED 点灯なら true
                    335:  private:
                    336:        FDDDevice *fdd {};
                    337: };
                    338: 
                    339: //
                    340: // NEWS の LED 情報
                    341: //
                    342: class StatusNEWS : public Status
                    343: {
                    344:  public:
                    345:        StatusNEWS(NewsCtlrDevice *newsctlr_) {
                    346:                newsctlr = newsctlr_;
                    347:        }
                    348:        virtual ~StatusNEWS() override = default;
                    349: 
                    350:        bool Poll() override {
                    351:                return MODIFY(led, newsctlr->GetLED());
                    352:        }
                    353: 
                    354:        uint led {};
                    355:  private:
                    356:        NewsCtlrDevice *newsctlr {};
                    357: };
                    358: 
                    359: 
1.1       root      360: // インジケータの初期化
                    361: void
                    362: WXStatusPanel::InitIndicators()
                    363: {
1.1.1.7   root      364:        Status *stat;
1.1.1.6   root      365:        Indicator *ind;
                    366: 
1.1       root      367:        // パフォーマンスカウンタ
1.1.1.7   root      368:        ind = new Indicator(Indicator::PERF, &WXStatusPanel::DrawPerf,
                    369:                8/* >>>9999% */, NULL);
1.1.1.6   root      370:        ind->dclick = &WXStatusPanel::DClickPerf;
                    371:        indicators.emplace_back(ind);
1.1       root      372: 
                    373:        // SCSI
                    374:        // SPC の接続済みデバイスリストから取得。
                    375:        // (ホストアダプタ2つ目のことは考えてない)
1.1.1.6   root      376:        auto spc = gMainApp.FindObject<SPCDevice>(OBJ_SPC);
                    377:        if (spc) {
1.1.1.7   root      378:                stat = new StatusSCSI(spc->GetSCSIBus());
                    379:                stats.emplace_back(stat);
                    380: 
1.1.1.6   root      381:                const std::vector<SCSIDevice *>& conn = spc->GetConnectedDevices();
                    382:                for (const auto& dev : conn) {
                    383:                        SCSI::DevType devtype = dev->GetDevType();
                    384:                        if (devtype == SCSI::DevType::Initiator) {
                    385:                                continue;
                    386:                        }
                    387:                        int scsiid = dev->GetMyID();
                    388: 
                    389:                        // 文字列は OnSCSIMediaChanged() でセットする。
1.1.1.7   root      390:                        ind = new Indicator(Indicator::SCSI0 + scsiid,
                    391:                                &WXStatusPanel::DrawSCSI, 3, stat);
1.1.1.6   root      392:                        ind->contextmenu = &WXStatusPanel::ContextMenuCD;
                    393:                        ind->dev = dev;
                    394:                        ind->panel = new wxPanel(this);
                    395:                        // このパネルがフォーカスを受け取らないようにする。
                    396:                        // StatusPanel がフォーカスを持っていてもキー入力を MainFrame に渡す
                    397:                        // ようにしているため、StatusPanel のフォーカスを奪ってはいけない。
                    398:                        ind->panel->SetCanFocus(false);
1.1.1.3   root      399: 
1.1.1.6   root      400:                        indicators.emplace_back(ind);
                    401:                }
1.1       root      402:        }
                    403: 
1.1.1.8 ! root      404:        // VirtIOBlock
        !           405:        for (int i = 0; i < 8; i++) {
        !           406:                auto dev = gMainApp.FindObject<VirtIOBlockDevice>(OBJ_VIRTIO_BLOCK(i));
        !           407:                if (dev) {
        !           408:                        stat = new StatusVBlk(dev);
        !           409:                        stats.emplace_back(stat);
        !           410: 
        !           411:                        std::string label = string_format("VB%u", i);
        !           412:                        if (dev->GetWriteMode() == SCSIDisk::RW::WriteIgnore) {
        !           413:                                label += "\x02\x03";
        !           414:                        }
        !           415:                        ind = new Indicator(Indicator::VBLK0 + i, &WXStatusPanel::DrawVBlk,
        !           416:                                label, stat);
        !           417:                        ind->dev = dev;
        !           418:                        indicators.emplace_back(ind);
        !           419:                }
        !           420:        }
        !           421: 
1.1       root      422:        // ネットワーク
1.1.1.7   root      423:        for (int i = 0; i < 2; i++) {
                    424:                auto hostnet = gMainApp.FindObject<HostNetDevice>(OBJ_HOSTNET(i));
                    425:                if (hostnet) {
                    426:                        auto statnet = new StatusNet(hostnet);
                    427:                        stat = statnet;
                    428:                        stats.emplace_back(stat);
                    429: 
                    430:                        if (hostnet->GetDriverName() == "none") {
                    431:                                statnet->enable = false;
                    432:                        } else {
                    433:                                statnet->enable = true;
                    434:                        }
                    435:                        // \x1e は上向き矢印、\x1f は下向き矢印。
                    436:                        // ラベルは結局機種で変わる…
                    437:                        std::string label;
                    438:                        if (gMainApp.IsX68030()) {
                    439:                                label = string_format("LAN%d\x1e\x1f", i);
                    440:                        } else {
                    441:                                label = "LAN\x1e\x1f";
                    442:                        }
                    443:                        ind = new Indicator(Indicator::LAN0 + i, &WXStatusPanel::DrawNet,
                    444:                                label, stat);
                    445:                        indicators.emplace_back(ind);
1.1.1.2   root      446:                }
1.1       root      447:        }
                    448: 
1.1.1.5   root      449:        // FD
1.1.1.6   root      450:        for (int unit = 0; unit < FDCDevice::MAX_DRIVE; unit++) {
                    451:                auto fdd = gMainApp.FindObject<FDDDevice>(OBJ_FDD(unit));
                    452:                if (fdd) {
1.1.1.7   root      453:                        stat = new StatusFDD(fdd);
                    454:                        stats.emplace_back(stat);
1.1.1.6   root      455: 
                    456:                        // 文字列は OnFDDMediaChanged() でセットする。
1.1.1.7   root      457:                        ind = new Indicator(Indicator::FDD0 + unit,
                    458:                                &WXStatusPanel::DrawFD, 7, stat);
1.1.1.6   root      459: 
                    460:                        ind->contextmenu = &WXStatusPanel::ContextMenuFD;
                    461:                        ind->dev = fdd;
                    462:                        ind->panel = new wxPanel(this);
                    463:                        // フォーカスを受け取らない。少し上の CD のところ参照。
                    464:                        ind->panel->SetCanFocus(false);
                    465: 
                    466:                        indicators.emplace_back(ind);
1.1.1.5   root      467:                }
                    468:        }
                    469: 
1.1.1.6   root      470:        // NEWS の LED (2->1 の順で並べる)
1.1.1.7   root      471:        auto newsctlr = gMainApp.FindObject<NewsCtlrDevice>(OBJ_NEWSCTLR);
1.1.1.6   root      472:        if (newsctlr) {
1.1.1.7   root      473:                stat = new StatusNEWS(newsctlr);
                    474:                stats.emplace_back(stat);
                    475: 
                    476:                ind = new Indicator(Indicator::NEWSLED2, &WXStatusPanel::DrawNewsLED2,
                    477:                        "LED2", stat);
1.1.1.6   root      478:                indicators.emplace_back(ind);
                    479: 
1.1.1.7   root      480:                ind = new Indicator(Indicator::NEWSLED1, &WXStatusPanel::DrawNewsLED1,
                    481:                        "LED1", stat);
1.1.1.6   root      482:                indicators.emplace_back(ind);
                    483:        }
                    484: 
1.1.1.5   root      485:        // 電源 LED
1.1.1.7   root      486:        ind = new Indicator(Indicator::POWER, &WXStatusPanel::DrawPower,
                    487:                "POWER", NULL);
1.1.1.6   root      488:        indicators.emplace_back(ind);
1.1       root      489: }
                    490: 
                    491: // インジケータのレイアウト
                    492: void
                    493: WXStatusPanel::LayoutIndicators()
                    494: {
                    495:        int x;
                    496:        int y;
                    497:        int w;
                    498:        int h;
                    499: 
1.1.1.4   root      500:        // 上の枠はキャンバス上端から2px
                    501:        y = 2;
                    502:        // そこから上下の外枠と枠と文字の間
                    503:        h = font_height + 2 + 2;
                    504: 
1.1       root      505:        // まずは前から順に列挙して必要な幅を積算していく
                    506:        x = 0;
1.1.1.3   root      507:        for (auto ind : indicators) {
1.1.1.4   root      508:                // 前の枠とは1つ空ける
                    509:                x += 1;
1.1       root      510: 
                    511:                // 4 は、左右の外枠(1*2) と 枠と文字の間(1*2)
1.1.1.5   root      512:                int len = std::max(ind->minlen, (int)ind->text.length());
                    513:                w = len * font_width + 2 + 2;
1.1       root      514: 
1.1.1.4   root      515:                ind->rect = Rect(x, y, w, h);
1.1       root      516:                x += w;
                    517:        }
                    518: 
1.1.1.4   root      519:        // 右端も1つ空ける
                    520:        x += 1;
                    521: 
                    522:        // この x が最小サイズなのでこれをコントロールに設定。
                    523:        // (コントロールのサイズは WXMainFrame::Layout() が設定する)
                    524:        SetMinClientSize(wxSize(x, font_height + 8));
                    525: 
1.1       root      526:        // 全員を一旦右寄せ
                    527:        wxSize sz = GetClientSize();
                    528:        int offsetx = sz.x - x;
1.1.1.3   root      529:        for (auto ind : indicators) {
                    530:                ind->rect.Offset(offsetx, 0);
1.1       root      531:        }
                    532: 
                    533:        // そのうちパフォーマンスカウンタだけ中央寄せまで戻す
                    534:        if (indicators.size() > 0) {
1.1.1.3   root      535:                auto p = indicators.front();
1.1.1.4   root      536:                x = (sz.x / 2) - (p->rect.w / 2);
                    537:                if (p->rect.x > x) {
                    538:                        p->rect.x = x;
1.1.1.3   root      539:                }
                    540:        }
                    541: 
                    542:        // パネルをもっていれば、パネルをその位置に(再)設定。
                    543:        for (auto ind : indicators) {
1.1.1.5   root      544:                if (ind->panel) {
1.1.1.3   root      545:                        const auto& rect = ind->rect;
1.1.1.5   root      546:                        ind->panel->SetSize(rect.x, rect.y, rect.w, rect.h);
1.1       root      547:                }
                    548:        }
1.1.1.5   root      549: 
                    550:        refresh_background = true;
1.1       root      551: }
                    552: 
1.1.1.3   root      553: // 状態をチェック。
                    554: // 前回値からどれかでも変更があれば true を返す。
                    555: bool
                    556: WXStatusPanel::UpdateStat()
                    557: {
1.1.1.7   root      558:        bool mod = false;
1.1.1.3   root      559: 
1.1.1.7   root      560:        // 電源オン
                    561:        mod |= MODIFY(ispower, power->IsPower());
                    562:        mod |= MODIFY(powerled, power->GetPowerLED());
1.1.1.3   root      563: 
                    564:        // パフォーマンスカウンタ
1.1.1.7   root      565:        mod |= MODIFY(perf_mode, syncer->GetRunMode());
                    566:        mod |= MODIFY(perf_rate, syncer->GetPerfCounter());
1.1.1.3   root      567: 
1.1.1.7   root      568:        // それ以外
                    569:        for (const auto stat : stats) {
                    570:                mod |= stat->Poll();
1.1.1.3   root      571:        }
                    572: 
1.1.1.7   root      573:        return mod;
1.1.1.3   root      574: }
                    575: 
                    576: // 描画本体
                    577: void
1.1.1.4   root      578: WXStatusPanel::Draw()
1.1.1.3   root      579: {
                    580:        std::string text;
                    581: 
1.1.1.5   root      582:        // 指定された時だけ背景を再描画
                    583:        if (refresh_background) {
                    584:                refresh_background = false;
                    585:                bitmap.Fill(BGPANEL);
                    586:        }
                    587: 
1.1.1.3   root      588:        // なんとなく見栄えのため上下に薄い線を引く。
                    589:        // 四方を線で囲むとオーバーレイウィンドウのように見えるので上下だけ。
1.1.1.4   root      590:        wxSize size = GetSize();
                    591:        bitmap.DrawLineH(UD_GREY, 0, 0, size.x);
                    592:        bitmap.DrawLineH(UD_GREY, 0, size.y - 1, size.x);
1.1.1.3   root      593: 
                    594:        // 各インジケータを描画
                    595:        for (auto ind : indicators) {
1.1.1.4   root      596:                (this->*(ind->draw))(ind);
1.1.1.3   root      597:        }
                    598: }
                    599: 
1.1       root      600: // パフォーマンスカウンタ
                    601: void
1.1.1.4   root      602: WXStatusPanel::DrawPerf(const Indicator *ind)
1.1       root      603: {
1.1.1.4   root      604:        const Rect& rect = ind->rect;
1.1.1.2   root      605:        char text[16];
1.1.1.4   root      606:        const char *ffmark;
1.1       root      607: 
                    608:        // 枠
1.1.1.4   root      609:        bitmap.DrawRect(UD_GREY, rect);
1.1       root      610: 
                    611:        // 電源オフならここまで
                    612:        if (ispower == false) {
1.1.1.4   root      613:                bitmap.FillRect(BGPANEL,
                    614:                        rect.x + 1, rect.y + 1, rect.w - 2, rect.h - 2);
1.1       root      615:                return;
                    616:        }
                    617: 
1.1.1.2   root      618:        // 高速モードか通常モードかでいろいろ違う。
                    619:        // アイコンは
                    620:        // o 通常モード指示中ならアイコンなし
                    621:        // o 高速モード指示中なら >> (2つ)
                    622:        // o そのうち実際に高速動作なら  >>> (3つ)
                    623:        // パフォーマンス表示は
                    624:        // o 高速モード指示中なら倍率表記 (115% なら 1.2x)
                    625:        // o 通常モード指示中ならパーセント表記
1.1.1.6   root      626:        if ((perf_mode & Syncer::SCHED_SYNC) == 0) {
1.1.1.2   root      627:                // 高速モード指示
1.1       root      628:                if (perf_mode == 0) {
1.1.1.2   root      629:                        // 高速走行中
1.1.1.4   root      630:                        ffmark = "\x01\x01\x01";
                    631:                } else {
                    632:                        ffmark = "\x01\x01 ";
1.1       root      633:                }
                    634: 
1.1.1.2   root      635:                // 倍率表記は1桁少ないので、表示用に最下位桁を四捨五入
                    636:                int rate = perf_rate + 5;
                    637:                snprintf(text, sizeof(text), "%2d.%1dx",
                    638:                        (rate / 100), (rate % 100) / 10);
                    639:        } else {
                    640:                // 通常モード指示
1.1.1.4   root      641:                ffmark = "   ";
1.1.1.2   root      642:                snprintf(text, sizeof(text), "%4d%%", perf_rate);
                    643:        }
1.1.1.4   root      644: 
                    645:        DrawStringSJIS(UD_RED, rect.x + 2, rect.y + 2, ffmark);
                    646:        DrawStringSJIS(rect.x + 2 + font_width * 3, rect.y + 2, text);
1.1       root      647: }
                    648: 
                    649: // SCSI デバイス側のアクセスランプ
                    650: // 本体ではなく各 SCSI デバイス側 (外付け HDD の前面とか) にあるやつ。
                    651: void
1.1.1.4   root      652: WXStatusPanel::DrawSCSI(const Indicator *ind)
1.1       root      653: {
1.1.1.7   root      654:        const StatusSCSI *stat = dynamic_cast<const StatusSCSI*>(ind->stat);
1.1.1.4   root      655:        Color fg;
                    656:        Color bg;
1.1.1.5   root      657:        int scsiid;
1.1.1.3   root      658:        uint idmask;
                    659: 
1.1.1.5   root      660:        scsiid = ind->GetSCSIID();
                    661:        assertmsg(scsiid >= 0, "id=%d", ind->id);
                    662:        idmask = 1U << scsiid;
1.1       root      663: 
1.1.1.7   root      664:        if (scsi_loaded[scsiid]) {
1.1.1.4   root      665:                fg = UD_BLACK;
1.1.1.3   root      666:        } else {
                    667:                fg = UD_GREY;
                    668:        }
                    669: 
1.1.1.7   root      670:        if ((stat->bsy & idmask) != 0) {
                    671:                if (stat->dataout) {
1.1.1.2   root      672:                        bg = UD_RED;
                    673:                } else {
                    674:                        bg = UD_YELLOW_GREEN;
                    675:                }
1.1       root      676:        } else {
                    677:                bg = BGPANEL;
                    678:        }
                    679: 
1.1.1.4   root      680:        DrawTextLED(ind, fg, bg);
1.1       root      681: }
                    682: 
1.1.1.8 ! root      683: // VirtIOBlock デバイスのアクセスランプ。
        !           684: void
        !           685: WXStatusPanel::DrawVBlk(const Indicator *ind)
        !           686: {
        !           687:        const StatusVBlk *stat = dynamic_cast<const StatusVBlk*>(ind->stat);
        !           688:        Color fg;
        !           689:        Color bg;
        !           690: 
        !           691:        fg = UD_BLACK;
        !           692:        if (stat->write_active) {
        !           693:                bg = UD_RED;
        !           694:        } else if (stat->read_active) {
        !           695:                bg = UD_YELLOW_GREEN;
        !           696:        } else {
        !           697:                bg = BGPANEL;
        !           698:        }
        !           699: 
        !           700:        DrawTextLED(ind, fg, bg);
        !           701: }
        !           702: 
1.1       root      703: // ネットワーク(LAN)
                    704: void
1.1.1.4   root      705: WXStatusPanel::DrawNet(const Indicator *ind)
1.1       root      706: {
1.1.1.7   root      707:        const StatusNet *stat = dynamic_cast<const StatusNet*>(ind->stat);
                    708:        const Rect& rect = ind->rect;
1.1.1.4   root      709:        Color fg;
                    710:        Color bg = BGPANEL;
1.1       root      711: 
1.1.1.7   root      712:        if (stat->enable) {
1.1.1.4   root      713:                fg = UD_BLACK;
1.1.1.7   root      714:                if (stat->tx_active || stat->rx_active) {
1.1.1.2   root      715:                        bg = UD_YELLOW_GREEN;
                    716:                }
1.1       root      717:        } else {
                    718:                fg = UD_GREY;
                    719:        }
                    720: 
1.1.1.2   root      721:        // 枠
1.1.1.4   root      722:        bitmap.FillRect(bg, rect);
                    723:        bitmap.DrawRect(UD_GREY, rect);
1.1.1.2   root      724: 
                    725:        int x = rect.x + 2;
                    726:        int y = rect.y + 2;
                    727: 
1.1.1.3   root      728:        for (int i = 0; i < ind->text.size(); i++) {
                    729:                auto c = ind->text[i];
1.1.1.2   root      730:                switch (c) {
                    731:                 case '\x1e':   // 上向き矢印
1.1.1.7   root      732:                        if (stat->tx_active) {
1.1.1.4   root      733:                                fg = UD_BLACK;
1.1.1.2   root      734:                        } else {
                    735:                                fg = UD_GREY;
                    736:                        }
                    737:                        break;
                    738:                 case '\x1f':   // 下向き矢印
1.1.1.7   root      739:                        if (stat->rx_active) {
1.1.1.4   root      740:                                fg = UD_BLACK;
1.1.1.2   root      741:                        } else {
                    742:                                fg = UD_GREY;
                    743:                        }
                    744:                        break;
                    745:                }
                    746:                SetTextColor(fg, bg);
1.1.1.4   root      747:                DrawChar1(x, y, c);
1.1.1.2   root      748:                x += font_width;
                    749:        }
                    750:        ResetTextColor();
1.1       root      751: }
                    752: 
1.1.1.5   root      753: // FD
                    754: void
                    755: WXStatusPanel::DrawFD(const Indicator *ind)
                    756: {
1.1.1.7   root      757:        const StatusFDD *stat = dynamic_cast<const StatusFDD*>(ind->stat);
                    758:        const Rect& rect = ind->rect;
1.1.1.5   root      759:        Rect iconrect;
                    760:        Color pal[3];
1.1.1.7   root      761:        int unit;
1.1.1.5   root      762:        enum {
                    763:                BG = 0,
                    764:                FG,
                    765:                IN,
                    766:        };
                    767: 
                    768:        unit = ind->GetFDUnit();
                    769: 
                    770:        pal[BG] = BGPANEL;
1.1.1.7   root      771:        if (fd_loaded[unit]) {
1.1.1.5   root      772:                pal[FG] = UD_BLACK;
                    773:        } else {
                    774:                pal[FG] = UD_GREY;
                    775:        }
                    776: 
                    777:        // まず枠とテキストを通常描画
                    778:        DrawTextLED(ind, pal[FG], pal[BG]);
                    779: 
                    780:        // 続いて 5,6文字目の空き地に四角いインジケータを描画。
                    781:        // 同じ色で済むので先に描画する。
                    782:        iconrect.x = rect.x + 2 + font_width * 5 + 1;
                    783:        iconrect.y = rect.y + 2 + 1;
                    784:        iconrect.w = font_width * 2 - 2;
                    785:        iconrect.h = font_height - 2;
                    786:        bitmap.DrawRect(pal[FG], iconrect);
                    787:        // ディスク挿入(取り出し可)なら黄緑点灯
1.1.1.7   root      788:        if (stat->eject_led) {
1.1.1.5   root      789:                iconrect.x += 1;
                    790:                iconrect.y += 1;
                    791:                iconrect.w -= 2;
                    792:                iconrect.h -= 2;
                    793:                bitmap.FillRect(UD_YELLOW_GREEN, iconrect);
                    794:        }
                    795: 
                    796:        // その後で 3,4文字目の空き地に丸いインジケータを描画。
                    797:        int dx = rect.x + 2 + font_width * 3;
                    798:        int dy = rect.y + 2;
                    799: 
                    800:        // アクセス LED はディスク非挿入時に点滅するケースがあって、
                    801:        // その場合、フチがグレーのまま中を黄緑で塗りつぶすのは見えづらいので
                    802:        // 中を塗りつぶす時はフチを濃くしたほうがいい。
1.1.1.7   root      803:        switch (stat->access_led) {
1.1.1.5   root      804:         case FDDDevice::LED::GREEN:
                    805:                pal[FG] = UD_BLACK;
                    806:                pal[IN] = UD_YELLOW_GREEN;
                    807:                break;
                    808:         case FDDDevice::LED::RED:
                    809:                pal[FG] = UD_BLACK;
                    810:                pal[IN] = UD_RED;
                    811:                break;
                    812:         default:
                    813:                pal[IN] = pal[BG];
                    814:                break;
                    815:        }
1.1.1.6   root      816:        bitmap.DrawBitmap(dx, dy, *accmark, pal);
1.1.1.5   root      817: }
                    818: 
                    819: /*static*/ const uint8
                    820: WXStatusPanel::AccessMark12[] = {
                    821:        0,0,0,0,1,1,1,0,0,0,0,0,
                    822:        0,0,1,1,2,2,2,1,1,0,0,0,
                    823:        0,1,2,2,2,2,2,2,2,1,0,0,
                    824:        0,1,2,2,2,2,2,2,2,1,0,0,
                    825:        1,2,2,2,2,2,2,2,2,2,1,0,
                    826:        1,2,2,2,2,2,2,2,2,2,1,0,
                    827:        1,2,2,2,2,2,2,2,2,2,1,0,
                    828:        0,1,2,2,2,2,2,2,2,1,0,0,
                    829:        0,1,2,2,2,2,2,2,2,1,0,0,
                    830:        0,0,1,1,2,2,2,1,1,0,0,0,
                    831:        0,0,0,0,1,1,1,0,0,0,0,0,
                    832:        0,0,0,0,0,0,0,0,0,0,0,0,
                    833: };
                    834: /*static*/ const uint8
                    835: WXStatusPanel::AccessMark16[] = {
                    836:        0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,
                    837:        0,0,0,1,1,2,2,2,2,2,1,1,0,0,0,0,
                    838:        0,0,1,2,2,2,2,2,2,2,2,2,1,0,0,0,
                    839:        0,1,2,2,2,2,2,2,2,2,2,2,2,1,0,0,
                    840:        0,1,2,2,2,2,2,2,2,2,2,2,2,1,0,0,
                    841:        1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,
                    842:        1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,
                    843:        1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,
                    844:        1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,
                    845:        1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,
                    846:        0,1,2,2,2,2,2,2,2,2,2,2,2,1,0,0,
                    847:        0,1,2,2,2,2,2,2,2,2,2,2,2,1,0,0,
                    848:        0,0,1,2,2,2,2,2,2,2,2,2,1,0,0,0,
                    849:        0,0,0,1,1,2,2,2,2,2,1,1,0,0,0,0,
                    850:        0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,
                    851:        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                    852: };
1.1.1.6   root      853: /*static*/ const uint8
                    854: WXStatusPanel::AccessMark24[] = {
                    855:        0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
                    856:        0,0,0,0,0,0,0,0, 0,1,1,1,1,1,1,0, 0,0,0,0,0,0,0,0,
                    857:        0,0,0,0,0,0,0,1, 1,2,2,2,2,2,2,1, 1,0,0,0,0,0,0,0,
                    858:        0,0,0,0,0,1,1,2, 2,2,2,2,2,2,2,2, 2,1,1,0,0,0,0,0,
                    859:        0,0,0,0,1,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,1,0,0,0,0,
                    860:        0,0,0,1,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,1,0,0,0,
                    861:        0,0,0,1,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,1,0,0,0,
                    862:        0,0,1,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,1,0,0,
                    863:        0,0,1,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,1,0,0,
                    864:        0,1,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,1,0,
                    865:        0,1,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,1,0,
                    866:        0,1,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,1,0,
                    867:        0,1,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,1,0,
                    868:        0,1,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,1,0,
                    869:        0,1,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,1,0,
                    870:        0,0,1,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,1,0,0,
                    871:        0,0,1,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,1,0,0,
                    872:        0,0,0,1,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,1,0,0,0,
                    873:        0,0,0,1,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,1,0,0,0,
                    874:        0,0,0,0,1,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,1,0,0,0,0,
                    875:        0,0,0,0,0,1,1,2, 2,2,2,2,2,2,2,2, 2,1,1,0,0,0,0,0,
                    876:        0,0,0,0,0,0,0,1, 1,2,2,2,2,2,2,1, 1,0,0,0,0,0,0,0,
                    877:        0,0,0,0,0,0,0,0, 0,1,1,1,1,1,1,0, 0,0,0,0,0,0,0,0,
                    878:        0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
                    879: };
                    880: 
                    881: // NEWS LED1
                    882: void
                    883: WXStatusPanel::DrawNewsLED1(const Indicator *ind)
                    884: {
1.1.1.7   root      885:        const StatusNEWS *stat = dynamic_cast<const StatusNEWS*>(ind->stat);
1.1.1.6   root      886:        Color bg;
                    887: 
1.1.1.7   root      888:        if ((stat->led & NewsCtlrDevice::LED_ORANGE) != 0) {
1.1.1.6   root      889:                bg = UD_ORANGE;
                    890:        } else {
                    891:                bg = BGPANEL;
                    892:        }
                    893:        DrawTextLED(ind, UD_BLACK, bg);
                    894: }
                    895: 
                    896: // NEWS LED2
                    897: void
                    898: WXStatusPanel::DrawNewsLED2(const Indicator *ind)
                    899: {
1.1.1.7   root      900:        const StatusNEWS *stat = dynamic_cast<const StatusNEWS*>(ind->stat);
1.1.1.6   root      901:        Color bg;
                    902: 
1.1.1.7   root      903:        if ((stat->led & NewsCtlrDevice::LED_GREEN) != 0) {
1.1.1.6   root      904:                bg = UD_GREEN;
                    905:        } else {
                    906:                bg = BGPANEL;
                    907:        }
                    908:        DrawTextLED(ind, UD_BLACK, bg);
                    909: }
1.1.1.5   root      910: 
                    911: // 電源 LED
1.1       root      912: void
1.1.1.4   root      913: WXStatusPanel::DrawPower(const Indicator *ind)
1.1       root      914: {
1.1.1.5   root      915:        Color bg;
                    916: 
                    917:        if (ispower) {
                    918:                if (powerled) {
                    919:                        bg = UD_YELLOW_GREEN;
                    920:                } else {
                    921:                        bg = UD_GREY;
                    922:                }
                    923:        } else {
                    924:                // XXX 電源オフが出来たら X68030 なら赤
                    925:                bg = BGPANEL;
                    926:        }
                    927: 
                    928:        DrawTextLED(ind, UD_BLACK, bg);
1.1       root      929: }
                    930: 
                    931: // 共通の描画処理。
1.1.1.3   root      932: // ind->text を前景色 fg、背景色 bg で描画するだけの場合。
1.1       root      933: void
1.1.1.4   root      934: WXStatusPanel::DrawTextLED(const Indicator *ind, Color fg, Color bg)
1.1       root      935: {
1.1.1.4   root      936:        const Rect& rect = ind->rect;
1.1       root      937: 
                    938:        // 枠
1.1.1.4   root      939:        bitmap.FillRect(bg, rect);
                    940:        bitmap.DrawRect(UD_GREY, rect);
1.1       root      941: 
                    942:        SetTextColor(fg, bg);
1.1.1.4   root      943:        DrawStringSJIS(rect.x + 2, rect.y + 2, ind->text.c_str());
1.1       root      944:        ResetTextColor();
                    945: }
                    946: 
                    947: // 左ダブルクリックイベント
                    948: void
                    949: WXStatusPanel::OnLeftDClick(wxMouseEvent& event)
                    950: {
                    951:        const wxPoint& pt = event.GetPosition();
                    952: 
1.1.1.3   root      953:        for (auto ind : indicators) {
1.1       root      954:                // dclick を処理できる枠内なら
1.1.1.4   root      955:                if (ind->rect.Contains(pt.x, pt.y) && ind->dclick != NULL) {
1.1.1.3   root      956:                        (this->*(ind->dclick))(ind);
1.1       root      957:                        break;
                    958:                }
                    959:        }
                    960: }
                    961: 
                    962: // パフォーマンスカウンタ枠へのダブルクリック
                    963: void
1.1.1.3   root      964: WXStatusPanel::DClickPerf(const Indicator *ind)
1.1       root      965: {
                    966:        // モードを切り替える
1.1.1.6   root      967:        syncer->RequestFullSpeed(!syncer->GetFullSpeed());
1.1       root      968: }
1.1.1.3   root      969: 
                    970: // コンテキストメニューイベント
                    971: void
                    972: WXStatusPanel::OnContextMenu(wxContextMenuEvent& event)
                    973: {
                    974:        wxPoint pos = ScreenToClient(event.GetPosition());
                    975: 
                    976:        for (auto ind : indicators) {
                    977:                // コンテキストメニューを処理できる枠内なら
1.1.1.5   root      978:                if (ind->contextmenu && ind->rect.Contains(pos.x, pos.y)) {
                    979:                        (this->*(ind->contextmenu))(ind);
1.1.1.3   root      980:                        break;
                    981:                }
                    982:        }
                    983: }
                    984: 
                    985: // CD 枠でのコンテキストメニュー
                    986: void
                    987: WXStatusPanel::ContextMenuCD(const Indicator *ind)
                    988: {
1.1.1.5   root      989:        int scsiid = ind->GetSCSIID();
                    990:        assertmsg(scsiid >= 0, "id=%d", ind->id);
                    991: 
1.1.1.6   root      992:        auto mainframe = dynamic_cast<WXMainFrame*>(GetParent());
                    993:        auto menu = mainframe->CreateSCSIRemovableMenu(scsiid);
1.1.1.5   root      994:        if (menu) {
                    995:                PopupMenu(menu);
                    996:        }
                    997: }
                    998: 
                    999: // FD 枠でのコンテキストメニュー
                   1000: void
                   1001: WXStatusPanel::ContextMenuFD(const Indicator *ind)
                   1002: {
                   1003:        int unit = ind->GetFDUnit();
                   1004:        assertmsg(unit >= 0, "id=%d", ind->id);
1.1.1.3   root     1005: 
1.1.1.6   root     1006:        auto mainframe = dynamic_cast<WXMainFrame*>(GetParent());
                   1007:        auto menu = mainframe->CreateFDMenu(unit);
1.1.1.3   root     1008:        if (menu) {
                   1009:                PopupMenu(menu);
                   1010:        }
                   1011: }
                   1012: 
                   1013: // SCSI メディア変更イベント (UIMessage イベント)
                   1014: void
                   1015: WXStatusPanel::OnSCSIMediaChanged(wxCommandEvent& event)
                   1016: {
1.1.1.5   root     1017:        Indicator *ind = NULL;
1.1.1.7   root     1018:        bool new_loaded;
1.1.1.3   root     1019: 
                   1020:        // 該当の Indicator を探す (見付かるはず)
1.1.1.5   root     1021:        int scsiid = event.GetInt();
                   1022:        int id = Indicator::SCSI0 + scsiid;
                   1023:        for (auto i : indicators) {
                   1024:                if (i->id == id) {
                   1025:                        ind = i;
1.1.1.3   root     1026:                        break;
                   1027:                }
                   1028:        }
1.1.1.5   root     1029:        assert(ind);
                   1030:        const auto disk = dynamic_cast<const SCSIDisk *>(ind->dev);
1.1.1.3   root     1031: 
                   1032:        // メディアの状態を一旦クリア
1.1.1.7   root     1033:        new_loaded = false;
1.1.1.3   root     1034: 
                   1035:        // ツールチップを設定
                   1036:        SCSI::DevType devtype = disk->GetDevType();
                   1037:        std::string tip = string_format("%s%d: ",
1.1.1.5   root     1038:                SCSI::GetDevTypeName(devtype), scsiid);
1.1.1.3   root     1039:        const std::string& path = disk->GetPathName();
                   1040:        // 同時にメディア状態もセット
                   1041:        if (path.empty()) {
                   1042:                tip += "-";
                   1043:        } else {
                   1044:                tip += path;
1.1.1.7   root     1045:                new_loaded = true;
1.1.1.3   root     1046:        }
                   1047:        switch (disk->GetWriteMode()) {
                   1048:         case SCSIDisk::RW::ReadOnly:
                   1049:                tip += "\n(Read Only)";
                   1050:                break;
                   1051:         case SCSIDisk::RW::WriteProtect:
                   1052:                tip += "\n(Write Protected)";
                   1053:                break;
                   1054:         case SCSIDisk::RW::WriteIgnore:
                   1055:                tip += "\n(Write Ignored)";
                   1056:                break;
                   1057:         default:
                   1058:                break;
                   1059:        }
1.1.1.5   root     1060:        ind->panel->SetToolTip(tip);
                   1061: 
                   1062:        // 書き込み無視だけ、これによって shutdown が必要かどうかという
                   1063:        // オペレーションに違いが出るため表示する。
                   1064:        // 無駄に幅を取らないためメディア挿入時のみ表示。
                   1065:        // MO のライトプロテクト表示は必要になったら考える…。
                   1066:        ind->text = string_format("%s%d", SCSI::GetDevTypeName(devtype), scsiid);
1.1.1.7   root     1067:        if (new_loaded) {
1.1.1.5   root     1068:                if (disk->GetWriteMode() == SCSIDisk::RW::WriteIgnore) {
                   1069:                        ind->text += "\x02\x03";
                   1070:                }
                   1071:        }
1.1.1.3   root     1072: 
                   1073:        // メディアのロード状態が変われば (再配置して) 再描画。
                   1074:        // 通常周期のタイマーによる更新チェックではメディア状態はチェックして
                   1075:        // いないので、ここで自発的に行う。
1.1.1.7   root     1076:        if (scsi_loaded[scsiid] != new_loaded) {
                   1077:                scsi_loaded[scsiid] = new_loaded;
1.1.1.3   root     1078: 
                   1079:                LayoutIndicators();
                   1080:                Refresh();
                   1081:        }
                   1082: }
1.1.1.5   root     1083: 
                   1084: // FDD メディア変更イベント (UIMessage イベント)
                   1085: void
                   1086: WXStatusPanel::OnFDDMediaChanged(wxCommandEvent& event)
                   1087: {
                   1088:        Indicator *ind = NULL;
                   1089:        bool new_loaded;
                   1090: 
                   1091:        // 該当の Indicator を探す (見付かるはず)
                   1092:        int unit = event.GetInt();
                   1093:        int id = Indicator::FDD0 + unit;
                   1094:        for (auto i : indicators) {
                   1095:                if (i->id == id) {
                   1096:                        ind = i;
                   1097:                        break;
                   1098:                }
                   1099:        }
                   1100:        assert(ind);
                   1101:        const auto fdd = dynamic_cast<const FDDDevice *>(ind->dev);
                   1102: 
                   1103:        // メディアの状態を一旦クリア
                   1104:        new_loaded = false;
                   1105: 
                   1106:        // ツールチップを設定
                   1107:        std::string tip = string_format("FD%d: ", unit);
                   1108:        const std::string& path = fdd->GetPathName();
                   1109:        // 同時にメディア状態もセット
                   1110:        if (path.empty()) {
                   1111:                tip += "-";
                   1112:        } else {
                   1113:                tip += path;
                   1114:                new_loaded = true;
                   1115:        }
                   1116:        switch (fdd->GetWriteMode()) {
                   1117:         case FDDDevice::RW::WriteProtect:
                   1118:                tip += "\n(Write Protected)";
                   1119:                break;
                   1120:         case FDDDevice::RW::WriteIgnore:
                   1121:                tip += "\n(Write Ignored)";
                   1122:                break;
                   1123:         default:
                   1124:                break;
                   1125:        }
                   1126:        ind->panel->SetToolTip(tip);
                   1127: 
                   1128:        ind->text = string_format("FD%d", fdd->GetUnitNo());
                   1129:        // 書き込み無視だけ表示する。無駄に幅を取らないためメディア挿入時のみ表示。
                   1130:        // 4文字分のマークの後ろに "WI" を追加。
                   1131:        if (new_loaded) {
                   1132:                if (fdd->GetWriteMode() == FDDDevice::RW::WriteIgnore) {
                   1133:                        ind->text += "    \x02\x03";
                   1134:                }
                   1135:        }
                   1136: 
                   1137:        // メディアのロード状態が変われば (再配置して) 再描画。
                   1138:        // 通常周期のタイマーによる更新チェックではメディア状態はチェックして
                   1139:        // いないので、ここで自発的に行う。
1.1.1.7   root     1140:        if (fd_loaded[unit] != new_loaded) {
                   1141:                fd_loaded[unit] = new_loaded;
1.1.1.5   root     1142: 
                   1143:                LayoutIndicators();
                   1144:                Refresh();
                   1145:        }
                   1146: }
                   1147: 
                   1148: // LED 状態変更イベント (UIMessage イベント)。
                   1149: //
                   1150: // 状態変更があったことをプッシュ通知する。主に、通常の更新頻度では
                   1151: // 間に合わない X68030 の電源 LED の 16Hz 点滅用。
                   1152: void
                   1153: WXStatusPanel::OnLEDChanged(wxCommandEvent& event)
                   1154: {
                   1155:        if (UpdateStat()) {
                   1156:                Refresh();
                   1157:        }
                   1158: }
                   1159: 
                   1160: 
                   1161: //
                   1162: // インジケータ情報
                   1163: //
                   1164: 
                   1165: // SCSI なら SCSI ID を返す。そうでなければ -1 を返す。
                   1166: int
                   1167: Indicator::GetSCSIID() const
                   1168: {
                   1169:        int scsiid = id - SCSI0;
                   1170:        if (0 <= scsiid && scsiid <= 7) {
                   1171:                return scsiid;
                   1172:        } else {
                   1173:                return -1;
                   1174:        }
                   1175: }
                   1176: 
                   1177: // FDD ならユニット番号を返す。そうでなければ -1 を返す。
                   1178: int
                   1179: Indicator::GetFDUnit() const
                   1180: {
                   1181:        int unit = id - FDD0;
                   1182:        if (0 <= unit && unit <= 3) {
                   1183:                return unit;
                   1184:        } else {
                   1185:                return -1;
                   1186:        }
                   1187: }

unix.superglobalmegacorp.com

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