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

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

unix.superglobalmegacorp.com

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