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

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

unix.superglobalmegacorp.com

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