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

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.4 ! root       27: #include "ethernet.h"
        !            28: #include "hostnet.h"
        !            29: #include "power.h"
1.1       root       30: #include "spc.h"
1.1.1.4 ! root       31: #include "sync.h"
1.1       root       32: 
                     33: WXStatusPanel *gStatusPanel;
                     34: 
                     35: wxBEGIN_EVENT_TABLE(WXStatusPanel, inherited)
                     36:        EVT_CLOSE(WXStatusPanel::OnClose)
                     37:        EVT_SHOW(WXStatusPanel::OnShow)
                     38:        EVT_SIZE(WXStatusPanel::OnSize)
                     39:        EVT_TIMER(wxID_ANY, WXStatusPanel::OnTimer)
                     40:        EVT_LEFT_DCLICK(WXStatusPanel::OnLeftDClick)
1.1.1.3   root       41:        EVT_CONTEXT_MENU(WXStatusPanel::OnContextMenu)
1.1       root       42: wxEND_EVENT_TABLE()
                     43: 
                     44: // ステータスパネルの更新頻度 [Hz]
                     45: static constexpr uint FPS = 10;
                     46: 
                     47: // style フラグ
                     48: // デフォルトは wxTAB_TRAVERSAL だがこれを外すので分かりづらい字面になる
                     49: static const long STATUS_PANEL_STYLE = 0;
                     50: 
                     51: // コンストラクタ
                     52: WXStatusPanel::WXStatusPanel(wxWindow *parent)
1.1.1.4 ! root       53:        : inherited(parent, wxDefaultSize, STATUS_PANEL_STYLE)
1.1       root       54: {
                     55:        timer.SetOwner(this);
                     56: 
                     57:        // インジケータ用のパラメータを用意。
                     58:        InitIndicators();
                     59: 
1.1.1.4 ! root       60:        FontChanged();
1.1       root       61: 
                     62:        // キー入力イベントをメインビューに転送。
                     63:        // このパネルへのキー入力は不要なのと、メインウィンドウ内のコントロール
                     64:        // フォーカスがこのステータスパネルとメインビューのどっちにあるかは
                     65:        // 分かりづらくて、こっちがフォーカス持ってしまうと (というか起動後は
                     66:        // こっちにある) VM にキー入力が出来ずに焦ることになるので、ここへの
                     67:        // キー入力イベントは全部メインビューに飛ばす。
                     68:        Connect(wxEVT_KEY_UP, wxKeyEventHandler(WXMainView::OnKeyUp), NULL,
                     69:                gMainView);
                     70:        Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(WXMainView::OnKeyDown), NULL,
                     71:                gMainView);
1.1.1.3   root       72: 
                     73:        // VM からのメディア変更通知を受け取る
                     74:        WXUIMessage::Connect(UIMessage::SCSI_MEDIA_CHANGE, this,
                     75:                wxCommandEventHandler(WXStatusPanel::OnSCSIMediaChanged));
1.1       root       76: }
                     77: 
1.1.1.2   root       78: // デストラクタ
                     79: WXStatusPanel::~WXStatusPanel()
                     80: {
1.1.1.4 ! root       81:        while (indicators.empty() == false) {
        !            82:                Indicator *ind = indicators.back();
        !            83:                indicators.pop_back();
        !            84:                delete ind;
        !            85:        }
        !            86:        WXUIMessage::Disconnect(UIMessage::SCSI_MEDIA_CHANGE,
        !            87:                wxCommandEventHandler(WXStatusPanel::OnSCSIMediaChanged));
1.1.1.2   root       88: }
                     89: 
1.1       root       90: // クローズイベント
                     91: void
                     92: WXStatusPanel::OnClose(wxCloseEvent& event)
                     93: {
                     94:        // クローズする前に更新を止める。
                     95:        timer.Stop();
                     96: }
                     97: 
                     98: // 表示/非表示変更イベント
                     99: // new した時は (デフォルトで表示状態なのでか状態に変更がないという扱いの
                    100: // ようで) イベントは飛んでこない。同様に new 直後に Show() を明示発行しても
                    101: // 状態に変更がないためイベントは飛んでこない。
                    102: // new 直後に Hide() すればイベントは飛んでくる。という動作をするようだ。
                    103: // そのため WXMainFrame 側で生成後に Show/Hide を起こしている。
                    104: void
                    105: WXStatusPanel::OnShow(wxShowEvent& event)
                    106: {
                    107:        if (event.IsShown()) {
                    108:                // 非表示→表示
                    109: 
                    110:                // 表示開始前に一度情報を取得
                    111:                UpdateStat();
                    112: 
                    113:                timer.Start(1000 / FPS);
                    114:        } else {
                    115:                // 表示→非表示
                    116: 
                    117:                timer.Stop();
                    118:        }
                    119: }
                    120: 
1.1.1.4 ! root      121: // フォントサイズ変更
1.1       root      122: void
1.1.1.4 ! root      123: WXStatusPanel::FontChanged()
1.1       root      124: {
1.1.1.4 ! root      125:        inherited::FontChanged();
        !           126: 
        !           127:        // インジケータを再レイアウト
        !           128:        LayoutIndicators();
1.1       root      129: 
                    130:        // コントロールの大きさを変更
1.1.1.4 ! root      131:        wxSize size = GetClientSize();
        !           132:        size.y = font_height + 8;
1.1       root      133:        SetClientSize(size);
                    134: }
                    135: 
                    136: // サイズ変更イベント
                    137: void
                    138: WXStatusPanel::OnSize(wxSizeEvent& event)
                    139: {
                    140:        // Mac ではウィンドウ作成時に 0 以下の値が来ることがある
                    141:        // GTK では 1 で来ることがある
                    142:        const wxSize& size = event.GetSize();
                    143:        if (size.x <= 1 || size.y <= 1) {
                    144:                return;
                    145:        }
                    146: 
1.1.1.4 ! root      147:        // 親クラス
        !           148:        inherited::OnSize(event);
1.1       root      149: 
                    150:        LayoutIndicators();
                    151: 
                    152:        // 再描画を指示
                    153:        Refresh();
                    154: }
                    155: 
                    156: // タイマーイベント
                    157: void
                    158: WXStatusPanel::OnTimer(wxTimerEvent& event)
                    159: {
                    160:        if (UpdateStat()) {
                    161:                Refresh();
                    162:        }
                    163: }
                    164: 
1.1.1.2   root      165: static const std::vector<int> data = {
                    166:        0x0b, 0x06, 0x0b, 0x06, 0x00, 0x4c, 0x55, 0x4e, 0x41, 0x74,
                    167:        0x69, 0x63, 0x20, 0x54, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x72,
                    168: };
                    169: 
1.1       root      170: // インジケータの初期化
                    171: void
                    172: WXStatusPanel::InitIndicators()
                    173: {
                    174:        // パフォーマンスカウンタ
1.1.1.3   root      175:        Indicator *perf = new Indicator(">>>9999%", &WXStatusPanel::DrawPerf);
                    176:        perf->dclick = &WXStatusPanel::DClickPerf;
1.1       root      177:        indicators.emplace_back(perf);
                    178: 
                    179:        // FD
                    180: 
                    181:        // SCSI
                    182:        // SPC の接続済みデバイスリストから取得。
                    183:        // (ホストアダプタ2つ目のことは考えてない)
                    184:        const std::vector<SCSIDevice *>& conn = gSPC->GetConnectedDevices();
                    185:        for (const auto& dev : conn) {
                    186:                SCSI::DevType devtype = dev->GetDevType();
1.1.1.3   root      187:                if (devtype == SCSI::DevType::Initiator) {
1.1       root      188:                        continue;
                    189:                }
1.1.1.3   root      190:                int id = dev->GetMyID();
1.1       root      191: 
1.1.1.3   root      192:                SCSIIndicator *si = new SCSIIndicator();
                    193:                si->text = string_format("%s%d", SCSI::GetDevTypeName(devtype), id);
                    194:                // 書き込み無視だけ、これによって shutdown が必要かどうかという
                    195:                // オペレーションに違いが出るため表示する。
                    196:                // MO (と FD の) ライトプロテクト表示は必要になったら考える…。
                    197:                const SCSIDisk *disk = dynamic_cast<const SCSIDisk *>(dev);
                    198:                assert(disk);
                    199:                if (disk->GetWriteMode() == SCSIDisk::RW::WriteIgnore) {
                    200:                        si->text += "\x02\x03";
                    201:                }
                    202:                si->draw = &WXStatusPanel::DrawSCSI;
                    203:                si->id = id;
                    204:                si->dev = dev;
                    205:                si->contextmenu = &WXStatusPanel::ContextMenuCD;
                    206:                si->panel = new wxPanel(this);
                    207:                // このパネルがフォーカスを受け取らないようにする。
                    208:                // StatusPanel がフォーカスを持っていてもキー入力を MainFrame に渡す
                    209:                // ようにしているため、StatusPanel のフォーカスを奪ってはいけない。
                    210:                si->panel->SetCanFocus(false);
                    211: 
                    212:                indicators.emplace_back(si);
1.1       root      213:        }
                    214:        // BSY 取得用
                    215:        scsibus = gSPC->GetSCSIBus();
                    216: 
                    217:        // ネットワーク
1.1.1.4 ! root      218:        if (gEthernet) {
        !           219:                hostnet = gEthernet->GetHostNet();
        !           220:                assert(hostnet);
        !           221:                if (hostnet->GetDriverName() == "none") {
1.1.1.2   root      222:                        net_ok = DISABLE;
1.1.1.4 ! root      223:                } else {
        !           224:                        net_ok = ENABLE;
1.1.1.2   root      225:                }
                    226:                // \x1e は上向き矢印、\x1f は下向き矢印
1.1.1.3   root      227:                Indicator *net = new Indicator("LAN\x1e\x1f", &WXStatusPanel::DrawNet);
                    228:                indicators.emplace_back(net);
1.1       root      229:        } else {
1.1.1.2   root      230:                net_ok = NOT_AVAILABLE;
1.1       root      231:        }
                    232: 
                    233:        // 電源 LED。点灯ロジックが分からないのでハリボテ。
1.1.1.3   root      234:        Indicator *power = new Indicator("POWER", &WXStatusPanel::DrawPower);
                    235:        indicators.emplace_back(power);
1.1.1.2   root      236: 
                    237:        // テスト用
                    238:        if (__predict_false(0||(bool)*gHostInfo)) {
                    239:                std::string s((const char *)GetParent()->GetLabel().mb_str());
                    240:                int i = 0;
                    241:                for (; i < 5; i++) {
                    242:                        s[i] += data[i];
                    243:                }
                    244:                for (; i < 9; i++) {
                    245:                        if (s[i] != data[i])
                    246:                                return;
                    247:                }
                    248:                for (; i < data.size(); i++) {
                    249:                        s.insert(s.begin() + i, data[i]);
                    250:                }
                    251:                GetParent()->SetLabel(s);
                    252:        }
1.1       root      253: }
                    254: 
                    255: // インジケータのレイアウト
                    256: void
                    257: WXStatusPanel::LayoutIndicators()
                    258: {
                    259:        int x;
                    260:        int y;
                    261:        int w;
                    262:        int h;
                    263: 
1.1.1.4 ! root      264:        // 上の枠はキャンバス上端から2px
        !           265:        y = 2;
        !           266:        // そこから上下の外枠と枠と文字の間
        !           267:        h = font_height + 2 + 2;
        !           268: 
1.1       root      269:        // まずは前から順に列挙して必要な幅を積算していく
                    270:        x = 0;
1.1.1.3   root      271:        for (auto ind : indicators) {
1.1.1.4 ! root      272:                // 前の枠とは1つ空ける
        !           273:                x += 1;
1.1       root      274: 
                    275:                // 4 は、左右の外枠(1*2) と 枠と文字の間(1*2)
1.1.1.3   root      276:                w = ind->text.length() * font_width + 2 + 2;
1.1       root      277: 
1.1.1.4 ! root      278:                ind->rect = Rect(x, y, w, h);
1.1       root      279:                x += w;
                    280:        }
                    281: 
1.1.1.4 ! root      282:        // 右端も1つ空ける
        !           283:        x += 1;
        !           284: 
        !           285:        // この x が最小サイズなのでこれをコントロールに設定。
        !           286:        // (コントロールのサイズは WXMainFrame::Layout() が設定する)
        !           287:        SetMinClientSize(wxSize(x, font_height + 8));
        !           288: 
1.1       root      289:        // 全員を一旦右寄せ
                    290:        wxSize sz = GetClientSize();
                    291:        int offsetx = sz.x - x;
1.1.1.3   root      292:        for (auto ind : indicators) {
                    293:                ind->rect.Offset(offsetx, 0);
1.1       root      294:        }
                    295: 
                    296:        // そのうちパフォーマンスカウンタだけ中央寄せまで戻す
                    297:        if (indicators.size() > 0) {
1.1.1.3   root      298:                auto p = indicators.front();
1.1.1.4 ! root      299:                x = (sz.x / 2) - (p->rect.w / 2);
        !           300:                if (p->rect.x > x) {
        !           301:                        p->rect.x = x;
1.1.1.3   root      302:                }
                    303:        }
                    304: 
                    305:        // パネルをもっていれば、パネルをその位置に(再)設定。
                    306:        for (auto ind : indicators) {
                    307:                auto si = dynamic_cast<SCSIIndicator *>(ind);
                    308:                if (si && si->panel) {
                    309:                        const auto& rect = ind->rect;
1.1.1.4 ! root      310:                        si->panel->SetSize(rect.x, rect.y, rect.w, rect.h);
1.1       root      311:                }
                    312:        }
                    313: }
                    314: 
1.1.1.3   root      315: // 状態をチェック。
                    316: // 前回値からどれかでも変更があれば true を返す。
                    317: bool
                    318: WXStatusPanel::UpdateStat()
                    319: {
                    320:        bool updated = false;
                    321: 
                    322:        // store に value を代入。更新されていれば updated を立てる。
                    323:        // value は一度だけ評価される。
                    324:        auto MODIFY = [&](auto& store, auto value) {
                    325:                bool rv = store != value;
                    326:                updated |= rv;
                    327:                store = value;
                    328:                return rv;
                    329:        };
                    330: 
                    331:        // 電源オンか
1.1.1.4 ! root      332:        MODIFY(ispower, gPower->IsPower());
1.1.1.3   root      333: 
                    334:        // パフォーマンスカウンタ
1.1.1.4 ! root      335:        MODIFY(perf_mode, gSync->GetRunMode());
        !           336:        MODIFY(perf_rate, gSync->GetPerfCounter());
1.1.1.3   root      337: 
                    338:        // FD
                    339: 
                    340:        // SCSI アクセス
                    341:        MODIFY(scsi_bsy, scsibus->GetBSY());
                    342:        // 転送フェーズで DataOut の時だけ書き込みとみなす
                    343:        bool out = (scsibus->GetPhase() == SCSI::Phase::Transfer)
                    344:                && (scsibus->GetXfer()  == SCSI::XferPhase::DataOut);
                    345:        MODIFY(scsi_out, out);
                    346: 
                    347:        // ネットワーク
                    348:        // パケット数が変化したとき、
                    349:        // およびその変化を監視しているアクティブ状態が変化したとき
                    350:        // に変更があったとしたいので二重になっている
                    351:        if (net_ok != NOT_AVAILABLE) {
1.1.1.4 ! root      352:                MODIFY(net_tx_active, MODIFY(net_tx_pkts, hostnet->GetTXPkts()));
        !           353:                MODIFY(net_rx_active, MODIFY(net_rx_pkts, hostnet->GetRXPkts()));
1.1.1.3   root      354:        }
                    355: 
                    356:        // 電源
                    357: 
                    358:        return updated;
                    359: }
                    360: 
                    361: // 描画本体
                    362: void
1.1.1.4 ! root      363: WXStatusPanel::Draw()
1.1.1.3   root      364: {
                    365:        std::string text;
                    366: 
                    367:        // なんとなく見栄えのため上下に薄い線を引く。
                    368:        // 四方を線で囲むとオーバーレイウィンドウのように見えるので上下だけ。
1.1.1.4 ! root      369:        wxSize size = GetSize();
        !           370:        bitmap.DrawLineH(UD_GREY, 0, 0, size.x);
        !           371:        bitmap.DrawLineH(UD_GREY, 0, size.y - 1, size.x);
1.1.1.3   root      372: 
                    373:        // 各インジケータを描画
                    374:        for (auto ind : indicators) {
1.1.1.4 ! root      375:                (this->*(ind->draw))(ind);
1.1.1.3   root      376:        }
                    377: }
                    378: 
1.1       root      379: // パフォーマンスカウンタ
                    380: void
1.1.1.4 ! root      381: WXStatusPanel::DrawPerf(const Indicator *ind)
1.1       root      382: {
1.1.1.4 ! root      383:        const Rect& rect = ind->rect;
1.1.1.2   root      384:        char text[16];
1.1.1.4 ! root      385:        const char *ffmark;
1.1       root      386: 
                    387:        // 枠
1.1.1.4 ! root      388:        bitmap.DrawRect(UD_GREY, rect);
1.1       root      389: 
                    390:        // 電源オフならここまで
                    391:        if (ispower == false) {
1.1.1.4 ! root      392:                bitmap.FillRect(BGPANEL,
        !           393:                        rect.x + 1, rect.y + 1, rect.w - 2, rect.h - 2);
1.1       root      394:                return;
                    395:        }
                    396: 
1.1.1.2   root      397:        // 高速モードか通常モードかでいろいろ違う。
                    398:        // アイコンは
                    399:        // o 通常モード指示中ならアイコンなし
                    400:        // o 高速モード指示中なら >> (2つ)
                    401:        // o そのうち実際に高速動作なら  >>> (3つ)
                    402:        // パフォーマンス表示は
                    403:        // o 高速モード指示中なら倍率表記 (115% なら 1.2x)
                    404:        // o 通常モード指示中ならパーセント表記
1.1.1.4 ! root      405:        if ((perf_mode & Sync::SCHED_SYNC) == 0) {
1.1.1.2   root      406:                // 高速モード指示
1.1       root      407:                if (perf_mode == 0) {
1.1.1.2   root      408:                        // 高速走行中
1.1.1.4 ! root      409:                        ffmark = "\x01\x01\x01";
        !           410:                } else {
        !           411:                        ffmark = "\x01\x01 ";
1.1       root      412:                }
                    413: 
1.1.1.2   root      414:                // 倍率表記は1桁少ないので、表示用に最下位桁を四捨五入
                    415:                int rate = perf_rate + 5;
                    416:                snprintf(text, sizeof(text), "%2d.%1dx",
                    417:                        (rate / 100), (rate % 100) / 10);
                    418:        } else {
                    419:                // 通常モード指示
1.1.1.4 ! root      420:                ffmark = "   ";
1.1.1.2   root      421:                snprintf(text, sizeof(text), "%4d%%", perf_rate);
                    422:        }
1.1.1.4 ! root      423: 
        !           424:        DrawStringSJIS(UD_RED, rect.x + 2, rect.y + 2, ffmark);
        !           425:        DrawStringSJIS(rect.x + 2 + font_width * 3, rect.y + 2, text);
1.1       root      426: }
                    427: 
                    428: // SCSI デバイス側のアクセスランプ
                    429: // 本体ではなく各 SCSI デバイス側 (外付け HDD の前面とか) にあるやつ。
                    430: void
1.1.1.4 ! root      431: WXStatusPanel::DrawSCSI(const Indicator *ind)
1.1       root      432: {
1.1.1.4 ! root      433:        Color fg;
        !           434:        Color bg;
1.1.1.3   root      435:        uint idmask;
                    436: 
                    437:        const auto si = dynamic_cast<const SCSIIndicator *>(ind);
                    438:        assert(si);
                    439:        idmask = 1U << si->GetId();
1.1       root      440: 
1.1.1.3   root      441:        if ((scsi_loaded & idmask) != 0) {
1.1.1.4 ! root      442:                fg = UD_BLACK;
1.1.1.3   root      443:        } else {
                    444:                fg = UD_GREY;
                    445:        }
                    446: 
                    447:        if ((scsi_bsy & idmask) != 0) {
1.1.1.2   root      448:                if (scsi_out) {
                    449:                        bg = UD_RED;
                    450:                } else {
                    451:                        bg = UD_YELLOW_GREEN;
                    452:                }
1.1       root      453:        } else {
                    454:                bg = BGPANEL;
                    455:        }
                    456: 
1.1.1.4 ! root      457:        DrawTextLED(ind, fg, bg);
1.1       root      458: }
                    459: 
                    460: // ネットワーク(LAN)
                    461: void
1.1.1.4 ! root      462: WXStatusPanel::DrawNet(const Indicator *ind)
1.1       root      463: {
1.1.1.4 ! root      464:        Color fg;
        !           465:        Color bg = BGPANEL;
        !           466:        const Rect& rect = ind->rect;
1.1       root      467: 
                    468:        if (net_ok) {
1.1.1.4 ! root      469:                fg = UD_BLACK;
1.1.1.2   root      470:                if (net_tx_active || net_rx_active) {
                    471:                        bg = UD_YELLOW_GREEN;
                    472:                }
1.1       root      473:        } else {
                    474:                fg = UD_GREY;
                    475:        }
                    476: 
1.1.1.2   root      477:        // 枠
1.1.1.4 ! root      478:        bitmap.FillRect(bg, rect);
        !           479:        bitmap.DrawRect(UD_GREY, rect);
1.1.1.2   root      480: 
                    481:        int x = rect.x + 2;
                    482:        int y = rect.y + 2;
                    483: 
1.1.1.3   root      484:        for (int i = 0; i < ind->text.size(); i++) {
                    485:                auto c = ind->text[i];
1.1.1.2   root      486:                switch (c) {
                    487:                 case '\x1e':   // 上向き矢印
                    488:                        if (net_tx_active) {
1.1.1.4 ! root      489:                                fg = UD_BLACK;
1.1.1.2   root      490:                        } else {
                    491:                                fg = UD_GREY;
                    492:                        }
                    493:                        break;
                    494:                 case '\x1f':   // 下向き矢印
                    495:                        if (net_rx_active) {
1.1.1.4 ! root      496:                                fg = UD_BLACK;
1.1.1.2   root      497:                        } else {
                    498:                                fg = UD_GREY;
                    499:                        }
                    500:                        break;
                    501:                }
                    502:                SetTextColor(fg, bg);
1.1.1.4 ! root      503:                DrawChar1(x, y, c);
1.1.1.2   root      504:                x += font_width;
                    505:        }
                    506:        ResetTextColor();
1.1       root      507: }
                    508: 
                    509: // 電源LED?
                    510: void
1.1.1.4 ! root      511: WXStatusPanel::DrawPower(const Indicator *ind)
1.1       root      512: {
1.1.1.4 ! root      513:        DrawTextLED(ind, UD_BLACK, UD_YELLOW_GREEN);
1.1       root      514: }
                    515: 
                    516: // 共通の描画処理。
1.1.1.3   root      517: // ind->text を前景色 fg、背景色 bg で描画するだけの場合。
1.1       root      518: void
1.1.1.4 ! root      519: WXStatusPanel::DrawTextLED(const Indicator *ind, Color fg, Color bg)
1.1       root      520: {
1.1.1.4 ! root      521:        const Rect& rect = ind->rect;
1.1       root      522: 
                    523:        // 枠
1.1.1.4 ! root      524:        bitmap.FillRect(bg, rect);
        !           525:        bitmap.DrawRect(UD_GREY, rect);
1.1       root      526: 
                    527:        SetTextColor(fg, bg);
1.1.1.4 ! root      528:        DrawStringSJIS(rect.x + 2, rect.y + 2, ind->text.c_str());
1.1       root      529:        ResetTextColor();
                    530: }
                    531: 
                    532: // 左ダブルクリックイベント
                    533: void
                    534: WXStatusPanel::OnLeftDClick(wxMouseEvent& event)
                    535: {
                    536:        const wxPoint& pt = event.GetPosition();
                    537: 
1.1.1.3   root      538:        for (auto ind : indicators) {
1.1       root      539:                // dclick を処理できる枠内なら
1.1.1.4 ! root      540:                if (ind->rect.Contains(pt.x, pt.y) && ind->dclick != NULL) {
1.1.1.3   root      541:                        (this->*(ind->dclick))(ind);
1.1       root      542:                        break;
                    543:                }
                    544:        }
                    545: }
                    546: 
                    547: // パフォーマンスカウンタ枠へのダブルクリック
                    548: void
1.1.1.3   root      549: WXStatusPanel::DClickPerf(const Indicator *ind)
1.1       root      550: {
                    551:        // モードを切り替える
1.1.1.4 ! root      552:        gSync->RequestFullSpeed(!gSync->GetFullSpeed());
1.1       root      553: }
1.1.1.3   root      554: 
                    555: // コンテキストメニューイベント
                    556: void
                    557: WXStatusPanel::OnContextMenu(wxContextMenuEvent& event)
                    558: {
                    559:        wxPoint pos = ScreenToClient(event.GetPosition());
                    560: 
                    561:        for (auto ind : indicators) {
                    562:                // コンテキストメニューを処理できる枠内なら
                    563:                const auto si = dynamic_cast<const SCSIIndicator *>(ind);
1.1.1.4 ! root      564:                if (si && si->contextmenu && ind->rect.Contains(pos.x, pos.y)) {
1.1.1.3   root      565:                        (this->*(si->contextmenu))(ind);
                    566:                        break;
                    567:                }
                    568:        }
                    569: }
                    570: 
                    571: // CD 枠でのコンテキストメニュー
                    572: void
                    573: WXStatusPanel::ContextMenuCD(const Indicator *ind)
                    574: {
                    575:        const auto si = dynamic_cast<const SCSIIndicator *>(ind);
                    576:        assert(si);
                    577: 
                    578:        auto menu = gMainFrame->CreateSCSIRemovableMenu(si->GetId());
                    579:        if (menu) {
                    580:                PopupMenu(menu);
                    581:        }
                    582: }
                    583: 
                    584: // SCSI メディア変更イベント (UIMessage イベント)
                    585: void
                    586: WXStatusPanel::OnSCSIMediaChanged(wxCommandEvent& event)
                    587: {
                    588:        SCSIIndicator *si = NULL;
                    589:        uint8 new_loaded;
                    590: 
                    591:        // 該当の Indicator を探す (見付かるはず)
                    592:        int id = event.GetInt();
                    593:        for (int i = 0; i < indicators.size(); i++) {
                    594:                si = dynamic_cast<SCSIIndicator *>(indicators[i]);
                    595:                if (si && si->GetId() == id) {
                    596:                        break;
                    597:                }
                    598:        }
                    599:        assert(si);
                    600:        const auto disk = dynamic_cast<const SCSIDisk *>(si->dev);
                    601: 
                    602:        // メディアの状態を一旦クリア
                    603:        new_loaded = scsi_loaded;
                    604:        new_loaded &= ~(1U << id);
                    605: 
                    606:        // ツールチップを設定
                    607:        SCSI::DevType devtype = disk->GetDevType();
                    608:        std::string tip = string_format("%s%d: ",
                    609:                SCSI::GetDevTypeName(devtype), id);
                    610:        const std::string& path = disk->GetPathName();
                    611:        // 同時にメディア状態もセット
                    612:        if (path.empty()) {
                    613:                tip += "-";
                    614:        } else {
                    615:                tip += path;
                    616:                new_loaded |= (1U << id);
                    617:        }
                    618:        switch (disk->GetWriteMode()) {
                    619:         case SCSIDisk::RW::ReadOnly:
                    620:                tip += "\n(Read Only)";
                    621:                break;
                    622:         case SCSIDisk::RW::WriteProtect:
                    623:                tip += "\n(Write Protected)";
                    624:                break;
                    625:         case SCSIDisk::RW::WriteIgnore:
                    626:                tip += "\n(Write Ignored)";
                    627:                break;
                    628:         default:
                    629:                break;
                    630:        }
                    631:        si->panel->SetToolTip(tip);
                    632: 
                    633:        // メディアのロード状態が変われば (再配置して) 再描画。
                    634:        // 通常周期のタイマーによる更新チェックではメディア状態はチェックして
                    635:        // いないので、ここで自発的に行う。
                    636:        if (scsi_loaded != new_loaded) {
                    637:                scsi_loaded = new_loaded;
                    638: 
                    639:                LayoutIndicators();
                    640:                Refresh();
                    641:        }
                    642: }

unix.superglobalmegacorp.com

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