Annotation of nono/wx/wxmainframe.cpp, revision 1.1.1.15

1.1       root        1: //
                      2: // nono
1.1.1.4   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
1.1.1.13  root        7: //
                      8: // メインウィンドウ
                      9: //
                     10: 
1.1.1.4   root       11: #include "wxmainframe.h"
1.1.1.13  root       12: #include "fontmanager.h"
1.1.1.15! root       13: #include "wxdipswwindow.h"
1.1.1.4   root       14: #include "wxdumpmonitor.h"
1.1.1.5   root       15: #include "wxlcdwindow.h"
1.1.1.4   root       16: #include "wxlogmonitor.h"
1.1.1.13  root       17: #include "wxlogsetting.h"
1.1.1.4   root       18: #include "wxmainview.h"
                     19: #include "wxmonitor.h"
                     20: #include "wxmpumonitor.h"
1.1.1.15! root       21: #include "wxpalettemonitor.h"
1.1.1.14  root       22: #include "wxplanemonitor.h"
                     23: #include "wxromwindow.h"
1.1.1.4   root       24: #include "wxsoftkey.h"
1.1.1.9   root       25: #include "wxstatuspanel.h"
1.1.1.11  root       26: #include "wxuimessage.h"
1.1.1.4   root       27: #include "wxversion.h"
1.1.1.13  root       28: #include "config.h"
1.1.1.14  root       29: #include "fdc.h"
                     30: #include "fdd.h"
1.1.1.3   root       31: #include "mainapp.h"
1.1.1.13  root       32: #include "nmi.h"
                     33: #include "power.h"
1.1.1.11  root       34: #include "spc.h"
1.1.1.15! root       35: #include "syncer.h"
1.1.1.4   root       36: #include "vm.h"
1.1.1.15! root       37: #include <algorithm>
1.1       root       38: 
1.1.1.13  root       39: // ID は 0 から (wxID_LOWEST = 5000 未満まで) 使えるっぽい。
                     40: // メニュー ID のうちウィンドウのオープン状態を維持する必要があるものは
                     41: // (ID が 0 から使えるのなら) 0 から割り当てて配列で管理してしまうのが
                     42: // 手っ取り早い。
                     43: // ウィンドウに割り当てるウィンドウ ID とメニューイベントで飛んでくる
                     44: // メニュー ID は互いに干渉しないはずなので、同じ値を使うことでメニューと
                     45: // ウィンドウの紐付けをする。
                     46: //
                     47: // ウィンドウ(サブウィンドウ)は細かくは以下のように4つに分類できるが、
                     48: // 処理上区別が必要なのは A. (デバッガの show コマンドとも共用できる
                     49: // サブウィンドウ) とそれ以外のサブウィンドウだけ。
                     50: //
                     51: // -----------+------------+----
                     52: // モニター   | テキスト   | A. 単純なテキストモニタウィンドウ
                     53: // ウィンドウ | モニター   |    (SPC, MFP などのデバイスのモニター)
                     54: //            | ウィンドウ +----
                     55: //            |            | B. それ以外のテキストモニターウィンドウ
                     56: //            |            |    (ログ、メモリのように表示位置があるもの、
                     57: //            |            |     CMMU のように構造があるもの)
                     58: //            +------------+----
                     59: //            | それ以外の | C. ビデオモニターウィンドウなど
                     60: //            | モニター   |    (ビットマッププレーン、TVRAM など)
                     61: //            | ウィンドウ |
                     62: // -----------+------------+----
                     63: // それ以外のウィンドウ    | D. ソフトウェアキーボードウィンドウなど
                     64: // ------------------------+----
                     65: enum {
                     66:        ID_SUBWIN_END_DUMMY = ID_SUBWIN_END,
                     67: 
                     68:        // ここから (ウィンドウでない)メニュー ID
1.1.1.15! root       69:        ID_EXIT,
1.1.1.13  root       70:        ID_RESTART_VM,
                     71:        ID_FULL_SPEED,
                     72: 
                     73:        ID_INPUT_START,
                     74:        ID_INPUT_CHAR,
                     75:        ID_INPUT_JP,
                     76:        ID_INPUT_END,
                     77: 
                     78:        ID_SCALE_START,
1.1.1.15! root       79:        ID_SCALE_END = ID_SCALE_START + 6,
1.1.1.13  root       80: 
                     81:        ID_FONTSIZE_START, // START 以降は fontsize_t と同じ順に並べること
                     82:        ID_FONTSIZE_12,
                     83:        ID_FONTSIZE_16,
1.1.1.15! root       84:        ID_FONTSIZE_24,
1.1.1.13  root       85:        ID_FONTSIZE_END,
                     86: 
                     87:        ID_MONRATE_START,
1.1.1.15! root       88:        ID_MONRATE_END = ID_MONRATE_START + 4,
1.1.1.13  root       89: 
                     90:        ID_SHOW_STATPANEL,
                     91: 
1.1.1.14  root       92:        // FD
                     93:        ID_FD_INSERT_0,
                     94:        ID_FD_INSERT_1,
                     95:        ID_FD_INSERT_2,
                     96:        ID_FD_INSERT_3,
                     97:        ID_FD_MISINSERT_0,
                     98:        ID_FD_MISINSERT_1,
                     99:        ID_FD_MISINSERT_2,
                    100:        ID_FD_MISINSERT_3,
                    101:        ID_FD_EJECT_0,
                    102:        ID_FD_EJECT_1,
                    103:        ID_FD_EJECT_2,
                    104:        ID_FD_EJECT_3,
                    105:        ID_FD_FORCE_0,
                    106:        ID_FD_FORCE_1,
                    107:        ID_FD_FORCE_2,
                    108:        ID_FD_FORCE_3,
                    109: 
1.1.1.13  root      110:        // CD/MO (リムーバブルデバイス)
                    111:        ID_CD_INSERT_0,
                    112:        ID_CD_INSERT_1,
                    113:        ID_CD_INSERT_2,
                    114:        ID_CD_INSERT_3,
                    115:        ID_CD_INSERT_4,
                    116:        ID_CD_INSERT_5,
                    117:        ID_CD_INSERT_6,
                    118:        ID_CD_INSERT_7,
                    119:        ID_CD_EJECT_0,
                    120:        ID_CD_EJECT_1,
                    121:        ID_CD_EJECT_2,
                    122:        ID_CD_EJECT_3,
                    123:        ID_CD_EJECT_4,
                    124:        ID_CD_EJECT_5,
                    125:        ID_CD_EJECT_6,
                    126:        ID_CD_EJECT_7,
                    127:        ID_CD_FORCE_0,
                    128:        ID_CD_FORCE_1,
                    129:        ID_CD_FORCE_2,
                    130:        ID_CD_FORCE_3,
                    131:        ID_CD_FORCE_4,
                    132:        ID_CD_FORCE_5,
                    133:        ID_CD_FORCE_6,
                    134:        ID_CD_FORCE_7,
                    135: 
                    136:        ID_MOUSEMODE,
1.1.1.14  root      137:        ID_POWER_BUTTON,
1.1.1.13  root      138:        ID_RESET_BUTTON,
                    139:        ID_NMI_BUTTON,
                    140:        ID_KEYBOARD_CONNECT,
                    141: 
                    142:        ID_local_end,   // 最後に置く (チェック用)
                    143: };
1.1.1.14  root      144: static_assert(ID_local_end - 1 <= (int)IDGROUP_MAINFRAME_END, "ID exceeded");
1.1.1.13  root      145: 
1.1.1.14  root      146: #define ID_FD_INSERT(id)       (ID_FD_INSERT_0 + (id))
                    147: #define ID_FD_MISINSERT(id)    (ID_FD_MISINSERT_0 + (id))
                    148: #define ID_FD_EJECT(id)                (ID_FD_EJECT_0 + (id))
                    149: #define ID_FD_FORCE(id)                (ID_FD_FORCE_0 + (id))
1.1.1.13  root      150: #define ID_CD_INSERT(id)       (ID_CD_INSERT_0 + (id))
                    151: #define ID_CD_EJECT(id)        (ID_CD_EJECT_0 + (id))
                    152: #define ID_CD_FORCE(id)        (ID_CD_FORCE_0 + (id))
                    153: 
1.1       root      154: wxBEGIN_EVENT_TABLE(WXMainFrame, inherited)
1.1.1.3   root      155:        EVT_CLOSE(WXMainFrame::OnClose)
1.1.1.15! root      156:        EVT_MENU(ID_EXIT, WXMainFrame::OnExit)
1.1       root      157: 
1.1.1.12  root      158:        EVT_MENU(ID_RESTART_VM, WXMainFrame::OnRestartVM)
1.1       root      159:        EVT_MENU(ID_FULL_SPEED, WXMainFrame::OnFullSpeed)
                    160:        EVT_UPDATE_UI(ID_FULL_SPEED, WXMainFrame::OnFullSpeedUI)
1.1.1.12  root      161:        EVT_MENU_RANGE(ID_INPUT_START + 1, ID_INPUT_END - 1,
                    162:                WXMainFrame::OnMenuInput)
                    163:        EVT_UPDATE_UI_RANGE(ID_INPUT_START + 1, ID_INPUT_END -1,
                    164:                WXMainFrame::OnMenuInputUI)
1.1.1.15! root      165:        EVT_MENU_RANGE(ID_SCALE_START, ID_SCALE_END,
1.1       root      166:                WXMainFrame::OnMenuScale)
1.1.1.15! root      167:        EVT_UPDATE_UI_RANGE(ID_SCALE_START, ID_SCALE_END,
1.1       root      168:                WXMainFrame::OnMenuScaleUI)
                    169:        EVT_MENU_RANGE(ID_FONTSIZE_START + 1, ID_FONTSIZE_END - 1,
                    170:                WXMainFrame::OnMenuFontSize)
                    171:        EVT_UPDATE_UI_RANGE(ID_FONTSIZE_START + 1, ID_FONTSIZE_END - 1,
                    172:                WXMainFrame::OnMenuFontSizeUI)
1.1.1.15! root      173:        EVT_MENU_RANGE(ID_MONRATE_START, ID_MONRATE_END,
1.1.1.5   root      174:                WXMainFrame::OnMenuMonRate)
1.1.1.15! root      175:        EVT_UPDATE_UI_RANGE(ID_MONRATE_START, ID_MONRATE_END,
1.1.1.5   root      176:                WXMainFrame::OnMenuMonRateUI)
1.1.1.9   root      177:        EVT_MENU(ID_SHOW_STATPANEL, WXMainFrame::OnShowStatusPanel)
                    178:        EVT_UPDATE_UI(ID_SHOW_STATPANEL, WXMainFrame::OnShowStatusPanelUI)
1.1.1.14  root      179:        EVT_MENU_RANGE(ID_FD_INSERT_0, ID_FD_INSERT_3,
                    180:                WXMainFrame::OnFDInsert)
                    181:        EVT_UPDATE_UI_RANGE(ID_FD_INSERT_0, ID_FD_INSERT_3,
                    182:                WXMainFrame::OnFDInsertUI)
                    183:        EVT_MENU_RANGE(ID_FD_EJECT_0, ID_FD_EJECT_3,
                    184:                WXMainFrame::OnFDEject)
                    185:        EVT_UPDATE_UI_RANGE(ID_FD_EJECT_0, ID_FD_EJECT_3,
                    186:                WXMainFrame::OnFDEjectUI)
                    187:        EVT_MENU_RANGE(ID_FD_FORCE_0, ID_FD_FORCE_3,
                    188:                WXMainFrame::OnFDForce)
                    189:        EVT_UPDATE_UI_RANGE(ID_FD_FORCE_0, ID_FD_FORCE_3,
                    190:                WXMainFrame::OnFDForceUI)
1.1.1.11  root      191:        EVT_MENU_RANGE(ID_CD_INSERT_0, ID_CD_INSERT_7,
                    192:                WXMainFrame::OnCDInsert)
                    193:        EVT_UPDATE_UI_RANGE(ID_CD_INSERT_0, ID_CD_INSERT_7,
                    194:                WXMainFrame::OnCDInsertUI)
                    195:        EVT_MENU_RANGE(ID_CD_EJECT_0, ID_CD_EJECT_7,
                    196:                WXMainFrame::OnCDEject)
                    197:        EVT_UPDATE_UI_RANGE(ID_CD_EJECT_0, ID_CD_EJECT_7,
                    198:                WXMainFrame::OnCDEjectUI)
                    199:        EVT_MENU_RANGE(ID_CD_FORCE_0, ID_CD_FORCE_7,
                    200:                WXMainFrame::OnCDForce)
                    201:        EVT_UPDATE_UI_RANGE(ID_CD_FORCE_0, ID_CD_FORCE_7,
                    202:                WXMainFrame::OnCDForceUI)
1.1.1.2   root      203:        EVT_MENU(ID_MOUSEMODE, WXMainFrame::OnMouseMode)
                    204:        EVT_UPDATE_UI(ID_MOUSEMODE, WXMainFrame::OnMouseModeUI)
1.1.1.14  root      205:        EVT_MENU(ID_POWER_BUTTON, WXMainFrame::OnPowerButton)
                    206:        EVT_UPDATE_UI(ID_POWER_BUTTON, WXMainFrame::OnPowerButtonUI)
1.1.1.9   root      207:        EVT_MENU(ID_RESET_BUTTON, WXMainFrame::OnResetButton)
1.1.1.13  root      208:        EVT_MENU(ID_NMI_BUTTON, WXMainFrame::OnNMIButton)
                    209:        EVT_MENU(ID_KEYBOARD_CONNECT, WXMainFrame::OnKeyboardConnect)
                    210:        EVT_UPDATE_UI(ID_KEYBOARD_CONNECT, WXMainFrame::OnKeyboardConnectUI)
1.1.1.10  root      211:        EVT_MENU_RANGE(0, ID_SUBWIN_END, WXMainFrame::OnWindow)
                    212:        EVT_UPDATE_UI_RANGE(0, ID_SUBWIN_END, WXMainFrame::OnWindowUI)
1.1.1.4   root      213:        EVT_MENU(wxID_ABOUT, WXMainFrame::OnAbout)
1.1       root      214: wxEND_EVENT_TABLE()
                    215: 
                    216: WXMainFrame::WXMainFrame(wxWindow *parent)
1.1.1.10  root      217:        : inherited(parent, wxID_ANY, "nono", wxDefaultPosition, wxDefaultSize,
1.1.1.6   root      218:                wxDEFAULT_FRAME_STYLE & ~wxMAXIMIZE_BOX & ~wxRESIZE_BORDER)
1.1       root      219: {
1.1.1.14  root      220:        VMType vmtype;
1.1.1.3   root      221:        vmtype = gMainApp.GetVMType();
1.1       root      222: 
1.1.1.15! root      223:        // デバイスを取得
        !           224:        power = GetPowerDevice();
        !           225:        syncer = GetSyncer();
        !           226:        // デバイスを取得。こっちはあるかどうかを調べる
        !           227:        keyboard = gMainApp.FindObject<Keyboard>(OBJ_KEYBOARD);
        !           228: 
1.1.1.12  root      229:        // メニュー
1.1       root      230:        wxMenuBar *menubar = new wxMenuBar();
1.1.1.12  root      231:        // メニュー > ファイル
1.1       root      232:        wxMenu *menuFile = new wxMenu();
1.1.1.9   root      233:        menuFile->Append(ID_RESTART_VM, _("&Restart VM"), "");
1.1.1.15! root      234:        menuFile->Append(ID_EXIT, _("E&xit"));
1.1.1.4   root      235:        menubar->Append(menuFile, _("&File"));
1.1       root      236: 
1.1.1.12  root      237:        // メニュー > 設定
                    238:        wxMenu *menuSet = new wxMenu();
                    239:        menuSet->Append(ID_FULL_SPEED, _("Full &Speed Mode"), "", wxITEM_CHECK);
1.1.1.15! root      240:        if (keyboard) {
        !           241:                wxMenu *menuSetInput = new wxMenu();
        !           242:                menuSetInput->AppendRadioItem(ID_INPUT_CHAR, _("By &Character"));
        !           243:                menuSetInput->AppendRadioItem(ID_INPUT_JP, _("&JP Keyboard"));
        !           244:                menuSet->AppendSubMenu(menuSetInput, _("&Key Input"));
        !           245:        }
1.1.1.12  root      246:        menubar->Append(menuSet, _("&Setting"));
                    247: 
                    248:        // メニュー > 表示
1.1       root      249:        wxMenu *menuDisplay = new wxMenu();
                    250:        wxMenu *menuViewScale = new wxMenu();
1.1.1.15! root      251:        int user_idx = CreateMainviewScaleTable();
        !           252:        for (int i = 0, end = view_scales.size(); i < end; i++) {
        !           253:                std::string text;
        !           254:                if (i == user_idx) {
        !           255:                        // ユーザ指定値は極力指定されたまま表示。
        !           256:                        text = string_format("x%g", view_scales[i]);
        !           257:                } else {
        !           258:                        // プリセットの数値は "0.5", "0.75", "1.0" と都合よく整形したい。
        !           259:                        text = string_format("x%.2f", view_scales[i]);
        !           260:                        if (text.size() == 5 && text[4] == '0') {
        !           261:                                text.pop_back();
        !           262:                        }
        !           263:                }
        !           264:                menuViewScale->AppendRadioItem(ID_SCALE_START + i, text);
        !           265:        }
1.1.1.4   root      266:        menuDisplay->AppendSubMenu(menuViewScale, _("&Scale"));
1.1       root      267:        wxMenu *menuFontSize = new wxMenu();
1.1.1.4   root      268:        menuFontSize->AppendRadioItem(ID_FONTSIZE_12, "1&2");
                    269:        menuFontSize->AppendRadioItem(ID_FONTSIZE_16, "1&6");
1.1.1.15! root      270:        menuFontSize->AppendRadioItem(ID_FONTSIZE_24, "2&4");
1.1.1.4   root      271:        menuDisplay->AppendSubMenu(menuFontSize, _("&Font Size"));
1.1.1.5   root      272:        wxMenu *menuMonRate = new wxMenu();
1.1.1.15! root      273:        user_idx = CreateMonRateTable();
        !           274:        for (int i = 0, end = monrates.size(); i < end; i++) {
        !           275:                std::string text;
        !           276:                switch (monrates[i]) {
        !           277:                 case 20:       text = _("High (&20Hz)");       break;
        !           278:                 case  5:       text = _("Middle (&5Hz)");      break;
        !           279:                 case  1:       text = _("Low (&1Hz)");         break;
        !           280:                 default:
        !           281:                        text = _("User specified") + string_format(" (%dHz)", monrates[i]);
        !           282:                        break;
        !           283:                }
        !           284:                menuMonRate->AppendRadioItem(ID_MONRATE_START + i, text);
        !           285:        }
1.1.1.5   root      286:        menuDisplay->AppendSubMenu(menuMonRate, _("&Monitor Speed"));
1.1.1.9   root      287:        menuDisplay->Append(ID_SHOW_STATPANEL, _("Show Status &Panel"), "",
                    288:                wxITEM_CHECK);
1.1.1.4   root      289:        menubar->Append(menuDisplay, _("&View"));
1.1       root      290: 
1.1.1.12  root      291:        // メニュー > デバイス
1.1       root      292:        wxMenu *menuDevice = new wxMenu();
1.1.1.11  root      293:        CreateRemovableMenu(menuDevice);
1.1.1.15! root      294:        if (keyboard) {
        !           295:                menuDevice->Append(ID_SUBWIN_SOFTKEY, _("Software &Keyboard"),
        !           296:                        "", wxITEM_CHECK);
        !           297:                menuDevice->Append(ID_MOUSEMODE, _("&Mouse Mode\tCTRL+F12"),
        !           298:                        "", wxITEM_CHECK);
        !           299:        }
1.1.1.14  root      300:        if (gMainApp.Has(VMCap::LUNA)) {
1.1.1.10  root      301:                menuDevice->Append(ID_SUBWIN_LCDPANEL, _("Front &LCD"),
1.1.1.5   root      302:                        "", wxITEM_CHECK);
                    303:        }
1.1.1.15! root      304:        if (gMainApp.Has(VMCap::LUNA | VMCap::NEWS)) {
        !           305:                menuDevice->Append(ID_SUBWIN_DIPSW, "&DIPSW", "", wxITEM_CHECK);
        !           306:        }
1.1.1.9   root      307:        menuDevice->AppendSeparator();
1.1.1.10  root      308:        wxMenu *menuOper = new wxMenu();
1.1.1.14  root      309:        wxItemKind power_button_kind;
                    310:        if (gMainApp.Has(VMCap::LUNA)) {
                    311:                power_button_kind = wxITEM_NORMAL;
                    312:        } else {
                    313:                power_button_kind = wxITEM_CHECK;
                    314:        }
                    315:        menuOper->Append(ID_POWER_BUTTON, _("Push &Power button"),
                    316:                "", power_button_kind);
1.1.1.10  root      317:        menuOper->Append(ID_RESET_BUTTON, _("Push &Reset button"));
1.1.1.14  root      318:        if (gMainApp.Has(VMCap::LUNA)) {
1.1.1.13  root      319:                menuOper->Append(ID_NMI_BUTTON, _("Push &ABORT button"));
1.1.1.15! root      320:        } else if (gMainApp.Has(VMCap::X68030)) {
1.1.1.13  root      321:                menuOper->Append(ID_NMI_BUTTON, _("Push &Interrupt button"));
                    322:        }
1.1.1.15! root      323:        // これ以降があればここにセパレータがほしい
        !           324:        bool sep = false;
        !           325:        if (keyboard) {
        !           326:                if (sep == false) {
        !           327:                        menuOper->AppendSeparator();
        !           328:                        sep = true;
        !           329:                }
        !           330:                menuOper->Append(ID_KEYBOARD_CONNECT, _("Connect &Keyboard"),
        !           331:                        "", wxITEM_CHECK);
        !           332:        }
        !           333:        menuDevice->AppendSubMenu(menuOper, _("&Operation"));
1.1.1.4   root      334:        menubar->Append(menuDevice, _("&Device"));
                    335: 
                    336:        // 機種によってモニタウィンドウを追加する
                    337: #define AppendIf(menu, id, label)      do { \
1.1.1.14  root      338:        VMCap vmcap_ = gMonitorManager->GetVMCap(id); \
                    339:        if (gMainApp.Has(vmcap_)) { \
1.1.1.10  root      340:                (menu)->Append((id), (label), "", wxITEM_CHECK); \
                    341:        } \
                    342: } while (0)
1.1.1.14  root      343: #define AppendIfSeparator(menu, vmcap_)        do { \
                    344:        if (gMainApp.Has(vmcap_)) { \
1.1.1.10  root      345:                (menu)->AppendSeparator(); \
1.1.1.4   root      346:        } \
                    347: } while (0)
1.1       root      348: 
1.1.1.12  root      349:        // メニュー > モニター
1.1       root      350:        wxMenu *menuMonitor = new wxMenu();
1.1.1.10  root      351:        AppendIf(menuMonitor, ID_MONITOR_SCHEDULER,     _("&Scheduler"));
1.1.1.5   root      352: 
1.1.1.4   root      353:        wxMenu *menuMPU = new wxMenu();
1.1.1.10  root      354:        AppendIf(menuMPU, ID_MONITOR_MPUREG,            _("&Register"));
                    355:        AppendIf(menuMPU, ID_MONITOR_MPUATC,              "&ATC");
1.1.1.15! root      356:        AppendIf(menuMPU, ID_MONITOR_INTERRUPT,         _("&Interrupt"));
1.1.1.14  root      357:        AppendIfSeparator(menuMPU, VMCap::M88K);
1.1.1.13  root      358:        AppendIf(menuMPU, ID_MONITOR_CMMU7,                      "CMMU#7" + _("(Inst)"));
1.1.1.10  root      359:        AppendIf(menuMPU, ID_MONITOR_ATC7,                        "ATC#7");
                    360:        AppendIf(menuMPU, ID_SUBWIN_CACHE7,                     _("Cache") + "#7");
1.1.1.14  root      361:        AppendIfSeparator(menuMPU, VMCap::M88K);
1.1.1.10  root      362:        AppendIf(menuMPU, ID_MONITOR_CMMU6,                       "CMMU#6" + _("(Data)"));
                    363:        AppendIf(menuMPU, ID_MONITOR_ATC6,                        "ATC#6");
                    364:        AppendIf(menuMPU, ID_SUBWIN_CACHE6,                     _("Cache") + "#6");
1.1.1.15! root      365:        menuMPU->AppendSeparator();
        !           366:        // MEMDUMPn のラベルは UpdateUI で書き直すのでここでは適当に
        !           367:        // 埋めておく。(empty だと怒られる)
        !           368:        for (int i = 0; i < MAX_MEMDUMP_MONITOR; i++) {
        !           369:                AppendIf(menuMPU, ID_MONITOR_MEMDUMP(i), "memdump");
        !           370:        }
        !           371:        menuMPU->AppendSeparator();
        !           372:        AppendIf(menuMPU, ID_SUBWIN_BRHIST,                     _("Branch &History"));
        !           373:        AppendIf(menuMPU, ID_SUBWIN_EXHIST,                     _("&Exception History"));
        !           374:        AppendIf(menuMPU, ID_SUBWIN_VECTOR,                     _("&Vector Table"));
        !           375:        menuMonitor->AppendSubMenu(menuMPU,
        !           376:                (gMainApp.Has(VMCap::M68K) ? "&MPU(MC68030)" : "&MPU(MC88xx0)"));
        !           377: 
        !           378:        if (gMainApp.Has(VMCap::LUNA)) {
        !           379:                wxMenu *menuXP = new wxMenu();
        !           380:                AppendIf(menuXP, ID_MONITOR_XPREG,              _("&Register"));
        !           381:                AppendIf(menuXP, ID_MONITOR_XPINTR,             _("&Interrupt"));
        !           382:                AppendIf(menuXP, ID_MONITOR_XPIO,               _("Internal &Devices"));
        !           383:                menuXP->AppendSeparator();
        !           384:                for (int i = 0; i < MAX_XPMEMDUMP_MONITOR; i++) {
        !           385:                        AppendIf(menuXP, ID_MONITOR_XPMEMDUMP(i), "memdump");
        !           386:                }
        !           387:                menuXP->AppendSeparator();
        !           388:                AppendIf(menuXP, ID_SUBWIN_XPBRHIST,    _("Branch &History"));
        !           389:                AppendIf(menuXP, ID_SUBWIN_XPEXHIST,    _("&Exception History"));
        !           390:                menuMonitor->AppendSubMenu(menuXP, "XP(HD647180)");
        !           391:        }
1.1.1.10  root      392: 
                    393:        // MONITOR_RTC は X68k の RTC、LUNA では MONITOR_MK48T02 だが今の所
                    394:        // NVRAM 側のことは表示してないのでラベルも RTC にしてある。
1.1.1.15! root      395:        wxMenu *menuDev = new wxMenu();
        !           396:        AppendIf(menuDev, ID_MONITOR_SPC,                         "SPC");
        !           397:        AppendIf(menuDev, ID_MONITOR_SCSIDEVS,          _("SCSI Devices"));
        !           398:        AppendIf(menuDev, ID_MONITOR_RTC,                         "RTC");
        !           399:        AppendIf(menuDev, ID_MONITOR_MK48T02,             "RTC");
        !           400:        AppendIf(menuDev, ID_MONITOR_DMAC,                        "DMAC");
        !           401:        AppendIf(menuDev, ID_MONITOR_MFP,                         "MFP");
        !           402:        AppendIf(menuDev, ID_MONITOR_FDC,                         "FDC");
        !           403:        AppendIf(menuDev, ID_MONITOR_SCC,                         "SCC");
        !           404:        AppendIf(menuDev, ID_MONITOR_SIO,                         "SIO");
        !           405:        AppendIf(menuDev, ID_MONITOR_PIO,                         "PIO0/PIO1");
        !           406:        AppendIf(menuDev, ID_MONITOR_KEYBOARD,          _("Keyboard/Mouse"));
        !           407:        AppendIf(menuDev, ID_MONITOR_LANCE,                       "Lance");
        !           408:        AppendIf(menuDev, ID_MONITOR_LCD,                         "LCD");
        !           409:        AppendIf(menuDev, ID_MONITOR_SYSCLK,            _("System Clock"));
        !           410:        AppendIf(menuDev, ID_MONITOR_CRTC,                        "CRTC");
        !           411:        AppendIf(menuDev, ID_MONITOR_LUNAVC,            _("Video Control"));
        !           412:        AppendIf(menuDev, ID_MONITOR_BT45x,                       "Bt454/458");
        !           413:        AppendIf(menuDev, ID_SUBWIN_PALETTE,            _("Palette Colormap"));
        !           414:        AppendIf(menuDev, ID_SUBWIN_TEXTPAL,            _("Text Palette Colormap"));
        !           415:        AppendIf(menuDev, ID_MONITOR_RENDERER,          _("Renderer"));
        !           416:        AppendIf(menuDev, ID_SUBWIN_LUNAFB,                     _("Bitmap Plane"));
        !           417:        AppendIf(menuDev, ID_SUBWIN_TVRAM,                      _("Text VRAM"));
        !           418:        AppendIf(menuDev, ID_MONITOR_ROMCONS,           _("ROM Console (provisional)"));
        !           419:        AppendIf(menuDev, ID_SUBWIN_ROM,                          "ROM");
        !           420:        menuMonitor->AppendSubMenu(menuDev, _("De&vice"));
1.1.1.5   root      421: 
                    422:        wxMenu *menuHost = new wxMenu();
1.1.1.10  root      423:        AppendIf(menuHost, ID_MONITOR_WXHOSTINFO,       _("Host &Information"));
                    424:        AppendIf(menuHost, ID_MONITOR_HOSTNET,          _("Host &Network"));
1.1.1.13  root      425:        AppendIf(menuHost, ID_MONITOR_HOSTCOM,          _("Host &Serial Port"));
1.1.1.5   root      426:        menuMonitor->AppendSubMenu(menuHost, _("&Host"));
                    427: 
1.1.1.15! root      428:        wxMenu *menuDebug = new wxMenu();
        !           429:        AppendIf(menuDebug, ID_SUBWIN_LOG,                      _("&Log"));
        !           430:        AppendIf(menuDebug, ID_MONITOR_BREAKPOINT,      _("&Breakpoint"));
        !           431:        menuDebug->AppendSeparator();
        !           432:        AppendIf(menuDebug, ID_SUBWIN_LOGSETTING,       _("Log Level &Setting"));
        !           433:        menuMonitor->AppendSubMenu(menuDebug, _("&Debug"));
        !           434: 
1.1.1.4   root      435:        menubar->Append(menuMonitor, _("&Monitor"));
                    436: 
1.1.1.12  root      437:        // メニュー > ヘルプ
1.1.1.4   root      438: #if defined(__WXOSX__)
                    439:        // OSX では wxID_ABOUT はリンゴメニューに入れるしきたりになっている。
                    440:        // Append() すると Quit より下に来てしまうので、Prepend() で上に追加。
                    441:        // 今のところヘルプメニューから About ダイアログを抜くとメニューが空に
                    442:        // なってしまうので、ヘルプメニューの追加ごと抑制する。
                    443:        menubar->OSXGetAppleMenu()->Prepend(wxID_ABOUT, _("About nono"));
                    444: #else
                    445:        wxMenu *menuHelp = new wxMenu();
                    446:        menuHelp->Append(wxID_ABOUT, _("About nono"));
                    447:        menubar->Append(menuHelp, _("&Help"));
                    448: #endif
                    449: 
1.1       root      450:        SetMenuBar(menubar);
                    451: 
                    452:        wxString title("nono");
                    453:        switch (vmtype) {
1.1.1.14  root      454:         case VMType::X68030:
1.1.1.3   root      455:                title += "(X68030)";
                    456:                break;
1.1.1.14  root      457:         case VMType::LUNA1:
1.1       root      458:                title += "(LUNA-I)";
                    459:                break;
1.1.1.14  root      460:         case VMType::LUNA88K:
1.1.1.15! root      461:                title += "(LUNA-88K)";
        !           462:                break;
        !           463:         case VMType::NEWS:
        !           464:                title += "(NWS-1750)";
1.1.1.3   root      465:                break;
                    466:         default:
1.1       root      467:                break;
                    468:        }
                    469:        SetTitle(title);
                    470: 
                    471:        // UpdateUI イベントは Idle 時に時折チェックされるらしいが、
                    472:        // (メインビューとサブウィンドウを合わせた) タイマーイベントの粒度が
                    473:        // 小さいためか、秒間120回とかいうレベルで UpdateUIEvent が飛んでくる
                    474:        // っぽい (全タイマーをとめたら治る模様)。
                    475:        // さすがにそんなに来られても気持ち悪いのと、どうせメニュー開いた瞬間
                    476:        // 表示しようとする前には一度飛んでくるのだから、アイドル時のチェックは
                    477:        // いらない気がする。間隔広げておいても、ぱっと見副作用はなさそうだけど
                    478:        // 念のため事象が分かりやすいように 10秒くらいにしておく。
                    479:        wxUpdateUIEvent::SetUpdateInterval(10000);
                    480: 
1.1.1.15! root      481:        // WXStatusPanel コンストラクタが mainview を参照するので
        !           482:        // mainview のほうを先に作成すること。
        !           483:        mainview = new WXMainView(this);
        !           484:        statuspanel = new WXStatusPanel(this);
1.1       root      485: 
1.1.1.9   root      486:        // SHOW イベントを最初にも一度起こしたいため
                    487:        // ステータスパネルを一旦非表示にする (これで SHOW(false) イベントが飛ぶ)
1.1.1.15! root      488:        statuspanel->Hide();
1.1.1.9   root      489:        const ConfigItem& item_show = gConfig->Find("show-statuspanel");
                    490:        if (item_show.AsInt() != 0) {
                    491:                // 必要なら改めて表示 (これで SHOW(true) イベントが飛ぶ)
1.1.1.15! root      492:                statuspanel->Show();
1.1.1.9   root      493:        }
                    494: 
1.1.1.13  root      495:        // Sizer 使わず自前でレイアウトする。
                    496:        SetAutoLayout(true);
1.1       root      497: 
1.1.1.4   root      498:        // Activate イベントは、このトップレベルウィンドウにウィンドウフォーカスが
                    499:        // 来た or 外れたことを示すので、wxFrame (というかたぶん wxTopLevelWindow)
                    500:        // を継承している WXMainFrameに飛んでくるのだが、処理の都合上 WXMainView で
                    501:        // 扱いたいので、そちらに回す。
                    502:        Connect(wxEVT_ACTIVATE, wxActivateEventHandler(WXMainView::OnActivate),
1.1.1.15! root      503:                NULL, mainview);
1.1.1.4   root      504: 
1.1.1.11  root      505:        // ウィンドウ表示後に続きの処理をするための単発アイドルイベント。
                    506:        Connect(wxEVT_IDLE, wxIdleEventHandler(WXMainFrame::OnIdle));
                    507: 
                    508:        // VM からの通知を接続
1.1.1.13  root      509:        WXUIMessage::Connect(UIMessage::APPEXIT, this,
1.1.1.11  root      510:                wxCommandEventHandler(WXMainFrame::OnExit));
                    511:        WXUIMessage::Connect(UIMessage::SCSI_MEDIA_FAILED, this,
1.1.1.14  root      512:                wxCommandEventHandler(WXMainFrame::OnInsertFailed));
                    513:        WXUIMessage::Connect(UIMessage::FDD_MEDIA_FAILED, this,
                    514:                wxCommandEventHandler(WXMainFrame::OnInsertFailed));
1.1.1.15! root      515:        if (gMainApp.Has(VMCap::M68K)) {
1.1.1.11  root      516:                WXUIMessage::Connect(UIMessage::HALT, this,
                    517:                        wxCommandEventHandler(WXMainFrame::OnHaltNotify));
                    518:        }
1.1       root      519: }
                    520: 
                    521: WXMainFrame::~WXMainFrame()
                    522: {
1.1.1.15! root      523:        WXUIMessage::Disconnect(UIMessage::APPEXIT, this,
1.1.1.13  root      524:                wxCommandEventHandler(WXMainFrame::OnExit));
1.1.1.15! root      525:        WXUIMessage::Disconnect(UIMessage::SCSI_MEDIA_FAILED, this,
1.1.1.14  root      526:                wxCommandEventHandler(WXMainFrame::OnInsertFailed));
1.1.1.15! root      527:        WXUIMessage::Disconnect(UIMessage::FDD_MEDIA_FAILED, this,
1.1.1.14  root      528:                wxCommandEventHandler(WXMainFrame::OnInsertFailed));
1.1.1.15! root      529:        if (gMainApp.Has(VMCap::M68K)) {
        !           530:                WXUIMessage::Disconnect(UIMessage::HALT, this,
1.1.1.13  root      531:                        wxCommandEventHandler(WXMainFrame::OnHaltNotify));
                    532:        }
1.1       root      533: }
                    534: 
1.1.1.11  root      535: // リムーバブルデバイス用のメニューを作成して menuDevice に追加する
                    536: void
                    537: WXMainFrame::CreateRemovableMenu(wxMenu *menuDevice)
                    538: {
                    539:        wxMenu *menu;
                    540:        bool added = false;
                    541: 
                    542:        // FD
1.1.1.15! root      543:        for (int unit = 0; unit < FDCDevice::MAX_DRIVE; unit++) {
        !           544:                fdd_array[unit] = gMainApp.FindObject<FDDDevice>(OBJ_FDD(unit));
        !           545:                if (fdd_array[unit]) {
1.1.1.14  root      546:                        menu = CreateFDMenu(unit);
                    547:                        std::string label = string_format("FD%d", unit);
                    548:                        menuDevice->AppendSubMenu(menu, label);
                    549:                        added = true;
                    550:                }
                    551:        }
1.1.1.11  root      552: 
                    553:        // CD, MO
1.1.1.15! root      554:        auto spc = gMainApp.FindObject<SPCDevice>(OBJ_SPC);
        !           555:        if (spc) {
        !           556:                for (int id = 0; id < 8; id++) {
        !           557:                        scsidev[id] = spc->GetTarget(id);
        !           558:                        if (scsidev[id]) {
        !           559:                                menu = CreateSCSIRemovableMenu(id);
        !           560:                                if (menu) {
        !           561:                                        std::string label = string_format("%s (ID%d)",
        !           562:                                                SCSI::GetDevTypeName(scsidev[id]->GetDevType()), id);
        !           563:                                        menuDevice->AppendSubMenu(menu, label);
        !           564:                                        added = true;
        !           565:                                }
1.1.1.11  root      566:                        }
                    567:                }
                    568:        }
                    569: 
                    570:        // 1つでも追加したらセパレータ
                    571:        if (added) {
                    572:                menuDevice->AppendSeparator();
                    573:        }
                    574: }
                    575: 
1.1.1.14  root      576: // FD 用のメニューを作成して返す。
                    577: wxMenu *
                    578: WXMainFrame::CreateFDMenu(int unit) const
                    579: {
                    580:        wxMenu *menu = new wxMenu();
                    581:        // Insert の実際のラベルは UpdateUI でセットする。
                    582:        // ただし何か入れておかないといけないので適当にセット。
                    583:        menu->Append(ID_FD_INSERT(unit), "Insert", "");
                    584:        // XXX 未実装
                    585:        //menu->Append(ID_FD_MISINSERT(unit), _("Insert incorrectly"), "");
                    586:        menu->Append(ID_FD_EJECT(unit), _("&Eject"), "");
                    587:        menu->Append(ID_FD_FORCE(unit), _("&Force Eject"), "");
                    588:        return menu;
                    589: }
                    590: 
1.1.1.11  root      591: // SCSI リムーバブルデバイス用のメニューを作成して返す。
                    592: // id はデバイスが接続されていること (リムーバブルデバイスであるかは問わない)。
                    593: // リムーバブルデバイスでなければ NULL を返す。
                    594: // メニューバーとポップアップメニュー共通。
                    595: wxMenu *
                    596: WXMainFrame::CreateSCSIRemovableMenu(uint id) const
                    597: {
                    598:        const auto *dev = scsidev[id];
                    599:        assert(dev);
                    600: 
                    601:        switch (dev->GetDevType()) {
                    602:         case SCSI::DevType::CD:
                    603:         case SCSI::DevType::MO:
                    604:         {
                    605:                wxMenu *menu = new wxMenu();
                    606:                // Insert の実際のラベルは UpdateUI でセットする。
                    607:                // ただし何か入れておかないといけないので適当にセット。
                    608:                menu->Append(ID_CD_INSERT(id), "Insert", "");
                    609:                menu->Append(ID_CD_EJECT(id), _("&Eject"), "");
                    610:                menu->Append(ID_CD_FORCE(id), _("&Force Eject"), "");
                    611:                return menu;
                    612:         }
                    613:         default:
                    614:                return NULL;
                    615:        }
                    616: }
                    617: 
1.1.1.12  root      618: // (設定反映などの) 初期化。
                    619: // 成功すれば true、失敗すれば false を返す。
                    620: bool
                    621: WXMainFrame::Init()
                    622: {
1.1.1.15! root      623:        if (!mainview->Init()) {
1.1.1.12  root      624:                return false;
                    625:        }
                    626: 
                    627:        return true;
                    628: }
                    629: 
1.1.1.13  root      630: bool
                    631: WXMainFrame::Layout()
                    632: {
                    633:        if (inherited::Layout() == false) {
                    634:                return false;
                    635:        }
                    636: 
1.1.1.15! root      637:        wxSize msize = statuspanel->GetMinClientSize();
        !           638:        wxSize ssize = statuspanel->GetClientSize();
        !           639:        wxSize vsize = mainview->GetClientSize();
1.1.1.13  root      640: 
1.1.1.15! root      641:        if (statuspanel->IsShown()) {
1.1.1.13  root      642:                ssize.y = msize.y;
                    643:        } else {
                    644:                ssize.y = 0;
                    645:        }
                    646: 
                    647:        wxSize size;
                    648:        size.x = std::max(msize.x, vsize.x);
                    649:        size.y = ssize.y + vsize.y;
                    650: 
                    651:        if (ssize.y != 0) {
1.1.1.15! root      652:                statuspanel->SetSize(0, 0, size.x, ssize.y);
1.1.1.13  root      653:        }
1.1.1.15! root      654:        mainview->SetSize(0, ssize.y, size.x, vsize.y);
1.1.1.13  root      655:        SetClientSize(size);
                    656: 
                    657:        return true;
                    658: }
                    659: 
1.1.1.11  root      660: // ウィンドウ作成イベント (を実現するためここではアイドルイベントを使う)
1.1.1.10  root      661: //
1.1.1.11  root      662: // 初期化(っぽい)もののうちコンストラクタでは早すぎるものは、コンストラクタ
                    663: // 直後に起こすこのイベント内で処理する。使えそうなイベントはいくつかあり、
                    664: // 自前の Create (今はもうない) -> WindowCreate -> Idle -> Paint の順で
                    665: // 起きるようだ。
                    666: // 自前の Create 時点では早すぎて、ここでサブウィンドウを作成するとサイズが 0
                    667: // みたいなウィンドウが一瞬出来てしまい GTK のワーニングが出る (その後サイズを
                    668: // 矯正すれば表示自体は出来る)。
1.1.1.10  root      669: // WindowCreate 時点ではその問題は起きないが、ここはまだメインウィンドウ表示
                    670: // 前なので、ここでサブウィンドウを表示した後メインウィンドウを表示すると
                    671: // (ウィンドウマネージャにもよるかもだが)、メインウィンドウがサブウィンドウを
                    672: // 隠してしまう。
1.1.1.11  root      673: // Idle イベント時点まで来ると上の2つの問題は回避できるようだ。
                    674: // Paint イベントの時点でもタイミング的には問題ないが、環境によっては(?)
                    675: // このイベント自体が飛んで来ないことがあるようだ。WXMainFrame の再描画は
1.1.1.13  root      676: // 子コントロールが行っており、そのため WXMainFrame 自身が再描画しなければ
                    677: // ならない領域は存在しないからかも知れないが詳細未調査。
1.1.1.11  root      678: void
                    679: WXMainFrame::OnIdle(wxIdleEvent& ev)
1.1       root      680: {
1.1.1.11  root      681:        // UIMessage の処理を開始する。
                    682:        // 少なくとも WXMainFrame のコンストラクタが完了した後のほうがいいはず。
                    683:        UIMessage::Attach(&WXUIMessage::Process);
                    684: 
1.1       root      685:        // ウィンドウを表示
1.1.1.10  root      686:        for (int i = 0; i < subwindow_start.size(); i++) {
                    687:                if (subwindow_start[i]) {
1.1       root      688:                        DoWindow(i, true);
                    689:                }
                    690:        }
                    691: 
1.1.1.9   root      692:        // 電源投入
1.1.1.15! root      693:        power->PowerButton();
1.1.1.10  root      694: 
                    695:        // 一度処理したら、このイベントを外す
1.1.1.11  root      696:        Disconnect(wxEVT_IDLE, wxIdleEventHandler(WXMainFrame::OnIdle));
1.1       root      697: }
                    698: 
1.1.1.3   root      699: // ウィンドウクローズイベント
                    700: void
                    701: WXMainFrame::OnClose(wxCloseEvent& event)
                    702: {
1.1.1.9   root      703:        // ステータスパネルの更新を停止
1.1.1.15! root      704:        statuspanel->Close();
1.1.1.13  root      705:        // メインビューの描画を停止
1.1.1.15! root      706:        mainview->Close();
1.1.1.9   root      707: 
1.1.1.3   root      708:        // サブウィンドウを全部閉じる
1.1.1.10  root      709:        for (int i = 0; i < ID_SUBWIN_MAX; i++) {
1.1.1.4   root      710:                if ((bool)windows[i]) {
1.1.1.3   root      711:                        windows[i]->Close();
                    712:                }
                    713:        }
                    714: 
                    715:        // VM を解放
1.1.1.4   root      716:        gVM->Dispose();
1.1.1.3   root      717: 
                    718:        // 後はデフォルト処理
                    719:        event.Skip();
                    720: }
                    721: 
1.1.1.12  root      722: // メニューの「Restart VM」イベント
                    723: void
                    724: WXMainFrame::OnRestartVM(wxCommandEvent& event)
                    725: {
1.1.1.15! root      726:        power->MakeRestart();
1.1.1.12  root      727: }
                    728: 
                    729: // メニューの「終了」イベント
                    730: void
                    731: WXMainFrame::OnExit(wxCommandEvent& event)
                    732: {
                    733:        // ウィンドウを閉じる
                    734:        Close();
                    735: }
                    736: 
1.1       root      737: // メニューの「高速モード」イベント
                    738: void
                    739: WXMainFrame::OnFullSpeed(wxCommandEvent& event)
                    740: {
                    741:        if (event.IsChecked()) {
                    742:                // チェックが入ったので、高速モードにする
1.1.1.15! root      743:                syncer->RequestFullSpeed(true);
1.1       root      744:        } else {
                    745:                // チェックが消えたので、通常モードにする
1.1.1.15! root      746:                syncer->RequestFullSpeed(false);
1.1       root      747:        }
                    748: }
                    749: 
                    750: // メニューの「高速モード」UI
                    751: void
                    752: WXMainFrame::OnFullSpeedUI(wxUpdateUIEvent& event)
                    753: {
1.1.1.15! root      754:        bool is_fullspeed = syncer->GetFullSpeed();
1.1       root      755:        event.Check(is_fullspeed);
                    756: }
                    757: 
1.1.1.12  root      758: // メニューの「設定 > 入力 > *」の共通イベント
1.1.1.6   root      759: void
1.1.1.12  root      760: WXMainFrame::OnMenuInput(wxCommandEvent& event)
1.1.1.6   root      761: {
1.1.1.12  root      762:        bool char_mode = (event.GetId() == ID_INPUT_CHAR);
                    763: 
1.1.1.15! root      764:        mainview->SetCharInputMode(char_mode);
1.1.1.6   root      765: }
                    766: 
1.1.1.12  root      767: // メニューの「設定 > 入力 > *」の共通 UI
1.1       root      768: void
1.1.1.12  root      769: WXMainFrame::OnMenuInputUI(wxUpdateUIEvent& event)
1.1       root      770: {
1.1.1.15! root      771:        bool char_mode = mainview->GetCharInputMode();
1.1.1.12  root      772: 
                    773:        if (char_mode) {
                    774:                event.Check(event.GetId() == ID_INPUT_CHAR);
                    775:        } else {
                    776:                event.Check(event.GetId() == ID_INPUT_JP);
                    777:        }
1.1       root      778: }
                    779: 
1.1.1.15! root      780: // スケール一覧
        !           781: /*static*/ std::vector<double>
        !           782: WXMainFrame::view_scales {
        !           783:        0.50,
        !           784:        0.75,
        !           785:        1.00,
        !           786:        1.50,
        !           787:        2.00,
        !           788: };
        !           789: 
        !           790: #define contains(v, key)       (std::find(v.begin(), v.end(), key) != v.end())
        !           791: 
        !           792: // 「表示 > スケール」のメニュー項目作成に必要な view_scale を作成し、
        !           793: // ユーザ指定値があれば view_scales[] 内でのインデックスを返す。
        !           794: // ユーザ指定値がなければ -1 を返す。
        !           795: int
        !           796: WXMainFrame::CreateMainviewScaleTable()
        !           797: {
        !           798:        // 設定ファイル mainview-scale で指定されたサイズを追加。
        !           799:        // 値はこの時点で WXMainView::screen_scale にセットされている。
        !           800:        double user_scale = WXMainView::screen_scale;
        !           801:        if (contains(view_scales, user_scale)) {
        !           802:                // プリセットと同じなら、このままでよい。
        !           803:        } else {
        !           804:                // 追加したらソート。
        !           805:                view_scales.push_back(user_scale);
        !           806:                std::sort(view_scales.begin(), view_scales.end());
        !           807: 
        !           808:                // ユーザ指定の値が何番目かを返す。指定されてなければ -1。
        !           809:                for (int i = 0, end = view_scales.size(); i < end; i++) {
        !           810:                        if (view_scales[i] == user_scale) {
        !           811:                                return i;
        !           812:                        }
        !           813:                }
        !           814:                // 見付からないことはないはずだが
        !           815:        }
        !           816:        return -1;
        !           817: }
        !           818: 
1.1       root      819: // メニューの「表示 > スケール > *」の共通イベント
                    820: void
                    821: WXMainFrame::OnMenuScale(wxCommandEvent& event)
                    822: {
1.1.1.15! root      823:        int idx = event.GetId() - ID_SCALE_START;
        !           824:        mainview->DoResize(view_scales[idx]);
1.1       root      825:        // 再レイアウト
1.1.1.13  root      826:        Layout();
1.1       root      827: }
                    828: 
                    829: // メニューの「表示 > スケール > *」の共通 UI
                    830: void
                    831: WXMainFrame::OnMenuScaleUI(wxUpdateUIEvent& event)
                    832: {
1.1.1.15! root      833:        int idx = event.GetId() - ID_SCALE_START;
        !           834:        double current_scale = mainview->GetScale();
1.1       root      835: 
1.1.1.15! root      836:        event.Check(view_scales[idx] == current_scale);
1.1       root      837: }
                    838: 
                    839: // メニューの「表示 > フォントサイズ > *」の共通イベント
                    840: void
                    841: WXMainFrame::OnMenuFontSize(wxCommandEvent& event)
                    842: {
1.1.1.5   root      843:        FontId fontid;
1.1       root      844: 
1.1.1.3   root      845:        assertmsg(
1.1.1.15! root      846:                ID_FONTSIZE_12 <= event.GetId() && event.GetId() <= ID_FONTSIZE_24,
1.1.1.3   root      847:                "event.GetId()=%d", event.GetId());
1.1       root      848:        switch (event.GetId()) {
                    849:         case ID_FONTSIZE_12:
1.1.1.5   root      850:                fontid = FontId::_6x12;
1.1       root      851:                break;
                    852:         case ID_FONTSIZE_16:
1.1.1.5   root      853:                fontid = FontId::_8x16;
1.1       root      854:                break;
1.1.1.15! root      855:         case ID_FONTSIZE_24:
        !           856:                fontid = FontId::_12x24;
        !           857:                break;
1.1       root      858:         default:
                    859:                __unreachable();
                    860:                break;
                    861:        }
                    862: 
1.1.1.13  root      863:        if (fontid != gFontManager->GetFontId()) {
                    864:                gFontManager->SetFont(fontid);
1.1       root      865: 
1.1.1.13  root      866:                // アクティブなサブウィンドウ全員にフォント変更通知
1.1.1.10  root      867:                for (int i = 0; i < ID_SUBWIN_MAX; i++) {
1.1.1.4   root      868:                        if ((bool)windows[i]) {
                    869:                                WXSubWindow *subwin =
                    870:                                        dynamic_cast<WXSubWindow *>(windows[i].get());
1.1.1.13  root      871:                                subwin->FontChanged();
1.1       root      872:                        }
                    873:                }
1.1.1.13  root      874:                // メインウィンドウはここで直接ステータスパネルに通知
1.1.1.15! root      875:                statuspanel->FontChanged();
1.1.1.9   root      876: 
                    877:                // ステータスパネルの大きさが変わるので再レイアウト
1.1.1.13  root      878:                Layout();
1.1       root      879:        }
                    880: }
                    881: 
                    882: // メニューの「表示 > フォントサイズ > *」共通 UI
                    883: void
                    884: WXMainFrame::OnMenuFontSizeUI(wxUpdateUIEvent& event)
                    885: {
1.1.1.13  root      886:        FontId current_size = gFontManager->GetFontId();
1.1.1.5   root      887:        FontId event_size = (FontId)(event.GetId() - (ID_FONTSIZE_START+1));
1.1       root      888: 
                    889:        event.Check(current_size == event_size);
                    890: }
                    891: 
1.1.1.15! root      892: // 更新頻度一覧
        !           893: /*static*/ std::vector<int>
        !           894: WXMainFrame::monrates {
        !           895:        20,
        !           896:        5,
        !           897:        1,
1.1.1.5   root      898: };
                    899: 
1.1.1.15! root      900: // 「表示 > モニタ更新頻度」のメニュー項目作成に必要な monrates を作成し、
        !           901: // ユーザ指定値があれば monrates[] 内のインデックスを返す。
        !           902: // ユーザ指定値がなければ -1 を返す。
        !           903: int
        !           904: WXMainFrame::CreateMonRateTable()
        !           905: {
        !           906:        // 設定ファイル monitor-rate で指定された値を追加。
        !           907:        // 値はこの時点で monitor_rate にセットされている。
        !           908:        int user_rate = monitor_rate;
        !           909:        if (contains(monrates, user_rate)) {
        !           910:                // プリセットと同じなら、このままでよい。
        !           911:        } else {
        !           912:                // 追加したら降順にソート。
        !           913:                monrates.push_back(user_rate);
        !           914:                std::sort(monrates.begin(), monrates.end(),
        !           915:                        [](int a, int b) { return a > b; }
        !           916:                );
        !           917: 
        !           918:                // ユーザ指定の値が何番目かを返す。指定されてなければ -1。
        !           919:                for (int i = 0, end = monrates.size(); i < end; i++) {
        !           920:                        if (monrates[i] == user_rate) {
        !           921:                                return i;
        !           922:                        }
        !           923:                }
        !           924:                // 見付からないことはないはずだが
        !           925:        }
        !           926:        return -1;
        !           927: }
        !           928: 
1.1.1.5   root      929: // メニューの「表示 > モニタ更新頻度 > *」の共通イベント
                    930: void
                    931: WXMainFrame::OnMenuMonRate(wxCommandEvent& event)
                    932: {
1.1.1.15! root      933:        int idx = event.GetId() - ID_MONRATE_START;
        !           934:        monitor_rate = monrates[idx];
1.1.1.5   root      935: 
                    936:        // アクティブなサブウィンドウのテキストパネル全員に通知
1.1.1.10  root      937:        for (int i = 0; i < ID_SUBWIN_MAX; i++) {
1.1.1.5   root      938:                if ((bool)windows[i]) {
                    939:                        auto *subwin = dynamic_cast<WXSubWindow *>(windows[i].get());
                    940:                        for (wxWindow *child : subwin->GetChildren()) {
1.1.1.14  root      941:                                auto *panel = dynamic_cast<WXMonitorPanel*>(child);
1.1.1.5   root      942:                                if (panel) {
                    943:                                        panel->SetRate(monitor_rate);
                    944:                                }
                    945:                        }
                    946:                }
                    947:        }
                    948: }
                    949: 
                    950: // メニューの「表示 > モニタ更新頻度 > *」共通 UI
                    951: void
                    952: WXMainFrame::OnMenuMonRateUI(wxUpdateUIEvent& event)
                    953: {
1.1.1.15! root      954:        int idx = event.GetId() - ID_MONRATE_START;
1.1.1.5   root      955: 
1.1.1.15! root      956:        event.Check(monrates[idx] == monitor_rate);
1.1.1.5   root      957: }
                    958: 
1.1.1.9   root      959: // メニューの「表示 > ステータスパネルを表示」
                    960: void
                    961: WXMainFrame::OnShowStatusPanel(wxCommandEvent& event)
                    962: {
                    963:        // enable ならチェックを付けようとして呼ばれた
                    964:        bool enable = event.IsChecked();
                    965: 
1.1.1.15! root      966:        statuspanel->Show(enable);
1.1.1.9   root      967: 
                    968:        // 再レイアウト
1.1.1.13  root      969:        Layout();
1.1.1.9   root      970: }
                    971: 
                    972: // メニューの「表示 > ステータスパネルを表示」UI
                    973: void
                    974: WXMainFrame::OnShowStatusPanelUI(wxUpdateUIEvent& event)
                    975: {
1.1.1.15! root      976:        event.Check(statuspanel->IsShown());
1.1.1.9   root      977: }
                    978: 
1.1.1.14  root      979: // メニューの「デバイス > FD > 挿入」
                    980: void
                    981: WXMainFrame::OnFDInsert(wxCommandEvent& event)
                    982: {
                    983:        int unit = event.GetId() - ID_FD_INSERT_0;
                    984:        const auto *fdd = fdd_array[unit];
                    985:        assert(fdd);
                    986: 
                    987:        std::string title(_("Open a FD image"));
                    988:        std::string wildcard("FD images (*.xdf;*.img;*.fs)"
                    989:                "|*.xdf;*.XDF;*.img;*.IMG;*.fs;*.FS"
                    990:                "|All files (*.*)|*.*");
                    991: 
                    992:        // ディレクトリは、まだ一度も使ってなければ VM ディレクトリにする
                    993:        if (current_dir.empty()) {
                    994:                current_dir = gMainApp.GetVMDir();
                    995:        }
                    996: 
                    997:        wxFileDialog dialog(this, title, current_dir, "", wildcard,
                    998:                wxFD_OPEN | wxFD_FILE_MUST_EXIST);
                    999:        if (dialog.ShowModal() == wxID_CANCEL) {
                   1000:                return;
                   1001:        }
                   1002:        auto path = std::string(dialog.GetPath());
                   1003:        InsertFD(unit, path);
                   1004: }
                   1005: 
                   1006: // メニューの「デバイス > FD > 挿入」UI
                   1007: void
                   1008: WXMainFrame::OnFDInsertUI(wxUpdateUIEvent& event)
                   1009: {
                   1010:        int unit = event.GetId() - ID_FD_INSERT_0;
                   1011:        const auto *fdd = fdd_array[unit];
                   1012:        assert(fdd);
                   1013: 
                   1014:        if (fdd->IsMediumLoaded()) {
                   1015:                event.SetText(_("Ex&change"));
                   1016:        } else {
                   1017:                event.SetText(_("&Insert"));
                   1018:        }
                   1019: }
                   1020: 
                   1021: // メニューの「デバイス > FD > 取り出し」
                   1022: void
                   1023: WXMainFrame::OnFDEject(wxCommandEvent& event)
                   1024: {
                   1025:        int unit = event.GetId() - ID_FD_EJECT_0;
                   1026: 
                   1027:        EjectFD(unit, false);
                   1028: }
                   1029: 
                   1030: // メニューの「デバイス > FD > 取り出し」UI
                   1031: void
                   1032: WXMainFrame::OnFDEjectUI(wxUpdateUIEvent& event)
                   1033: {
                   1034:        int unit = event.GetId() - ID_FD_EJECT_0;
                   1035:        FDDDevice *fdd = fdd_array[unit];
                   1036:        assert(fdd);
                   1037: 
                   1038:        // 挿入されてて取り出し可能な時のみ有効
                   1039:        event.Enable(fdd->IsMediumLoaded() && fdd->IsEjectEnable());
                   1040: }
                   1041: 
                   1042: // メニューの「デバイス > FD > 強制取り出し」
                   1043: void
                   1044: WXMainFrame::OnFDForce(wxCommandEvent& event)
                   1045: {
                   1046:        int unit = event.GetId() - ID_FD_FORCE_0;
                   1047: 
                   1048:        EjectFD(unit, true);
                   1049: }
                   1050: 
                   1051: // メニューの「デバイス > FD > 強制取り出し」UI
                   1052: void
                   1053: WXMainFrame::OnFDForceUI(wxUpdateUIEvent& event)
                   1054: {
                   1055:        int unit = event.GetId() - ID_FD_FORCE_0;
                   1056:        FDDDevice *fdd = fdd_array[unit];
                   1057:        assert(fdd);
                   1058: 
                   1059:        // 挿入されてて取り出し禁止の時のみ有効
                   1060:        event.Enable(fdd->IsMediumLoaded() && fdd->IsEjectEnable() == false);
                   1061: }
                   1062: 
1.1.1.11  root     1063: // メニューの「デバイス > CD/MO > 挿入」
                   1064: void
                   1065: WXMainFrame::OnCDInsert(wxCommandEvent& event)
                   1066: {
                   1067:        std::string title;
                   1068:        std::string wildcard;
                   1069: 
                   1070:        int id = event.GetId() - ID_CD_INSERT_0;
                   1071:        const auto *dev = scsidev[id];
                   1072:        assert(dev);
                   1073: 
                   1074:        switch (dev->GetDevType()) {
                   1075:         case SCSI::DevType::CD:
                   1076:                title = _("Open a CD image");
                   1077:                wildcard = "ISO images (*.iso;*.img)|*.iso;*.img;*.ISO;*.IMG";
                   1078:                break;
                   1079:         case SCSI::DevType::MO:
                   1080:                title = _("Open an MO image");
                   1081:                wildcard = "MO images (*.img;*.mos)|*.img;*.mos;*.IMG;*.MOS";
                   1082:                break;
                   1083:         default:
1.1.1.15! root     1084:                break;
1.1.1.11  root     1085:        }
                   1086:        wildcard += "|All files (*.*)|*.*";
                   1087: 
                   1088:        // ディレクトリは、まだ一度も使ってなければ VM ディレクトリにする
                   1089:        if (current_dir.empty()) {
                   1090:                current_dir = gMainApp.GetVMDir();
                   1091:        }
                   1092: 
                   1093:        wxFileDialog dialog(this, title, current_dir, "", wildcard,
                   1094:                wxFD_OPEN | wxFD_FILE_MUST_EXIST);
                   1095:        if (dialog.ShowModal() == wxID_CANCEL) {
                   1096:                return;
                   1097:        }
                   1098:        auto path = std::string(dialog.GetPath());
                   1099:        InsertCD(id, path);
                   1100: }
                   1101: 
                   1102: // メニューの「デバイス > CD/MO > 挿入」UI
                   1103: void
                   1104: WXMainFrame::OnCDInsertUI(wxUpdateUIEvent& event)
                   1105: {
                   1106:        int id = event.GetId() - ID_CD_INSERT_0;
                   1107:        SCSIDisk *disk = dynamic_cast<SCSIDisk *>(scsidev[id]);
                   1108:        assert(disk);
                   1109: 
                   1110:        if (disk->IsMediumLoaded()) {
                   1111:                event.SetText(_("Ex&change"));
                   1112:        } else {
                   1113:                event.SetText(_("&Insert"));
                   1114:        }
                   1115: }
                   1116: 
                   1117: // メニューの「デバイス > CD/MO > 取り出し」
                   1118: void
                   1119: WXMainFrame::OnCDEject(wxCommandEvent& event)
                   1120: {
                   1121:        int id = event.GetId() - ID_CD_EJECT_0;
                   1122: 
                   1123:        EjectCD(id, false);
                   1124: }
                   1125: 
                   1126: // メニューの「デバイス > CD/MO > 取り出し」UI
                   1127: void
                   1128: WXMainFrame::OnCDEjectUI(wxUpdateUIEvent& event)
                   1129: {
                   1130:        int id = event.GetId() - ID_CD_EJECT_0;
                   1131:        SCSIDisk *disk = dynamic_cast<SCSIDisk *>(scsidev[id]);
                   1132:        assert(disk);
                   1133: 
                   1134:        // 挿入されてて取り出し可能な時のみ有効
                   1135:        event.Enable(disk->IsMediumLoaded() &&
                   1136:                     disk->IsMediumRemovalAllowed());
                   1137: }
                   1138: 
                   1139: // メニューの「デバイス > CD/MO > 強制取り出し」
                   1140: void
                   1141: WXMainFrame::OnCDForce(wxCommandEvent& event)
                   1142: {
                   1143:        int id = event.GetId() - ID_CD_FORCE_0;
                   1144: 
                   1145:        EjectCD(id, true);
                   1146: }
                   1147: 
                   1148: // メニューの「デバイス > CD/MO > 強制取り出し」UI
                   1149: void
                   1150: WXMainFrame::OnCDForceUI(wxUpdateUIEvent& event)
                   1151: {
                   1152:        int id = event.GetId() - ID_CD_FORCE_0;
                   1153:        SCSIDisk *disk = dynamic_cast<SCSIDisk *>(scsidev[id]);
                   1154:        assert(disk);
                   1155: 
                   1156:        // 挿入されてて取り出し禁止の時のみ有効
                   1157:        event.Enable(disk->IsMediumLoaded() &&
                   1158:                     disk->IsMediumRemovalPrevented());
                   1159: }
                   1160: 
1.1.1.2   root     1161: // メニューの「デバイス > マウスモード」
                   1162: void
                   1163: WXMainFrame::OnMouseMode(wxCommandEvent& event)
                   1164: {
                   1165:        // enable ならチェックを付けようとして呼ばれた
                   1166:        bool enable = event.IsChecked();
                   1167: 
                   1168:        if (enable) {
                   1169:                // メッセージを表示したい
                   1170:        } else {
                   1171:                // メッセージを表示したい
                   1172:        }
                   1173: 
                   1174:        // マウスモードを設定
1.1.1.15! root     1175:        wxCommandEvent newev(NONO_EVT_MOUSEMODE, GetId());
        !          1176:        newev.SetEventObject(this);
        !          1177:        newev.SetInt(enable);
        !          1178:        ::wxPostEvent(mainview, newev);
1.1.1.2   root     1179: }
                   1180: 
                   1181: // メニューの「デバイス > マウスモード」UI
                   1182: void
                   1183: WXMainFrame::OnMouseModeUI(wxUpdateUIEvent& event)
                   1184: {
1.1.1.15! root     1185:        event.Check(mainview->GetMouseMode());
1.1.1.2   root     1186: }
                   1187: 
1.1.1.14  root     1188: // メニューの「デバイス > Push Power Button」イベント
                   1189: void
                   1190: WXMainFrame::OnPowerButton(wxCommandEvent& event)
                   1191: {
                   1192:        // LUNA はモーメンタリ動作、X68030 はオルタネート動作のスイッチ。
                   1193:        // この違いは VM 側で吸収するのでここはボタンを押したという動作だけ
                   1194:        // 通知する。
1.1.1.15! root     1195:        power->PowerButton();
1.1.1.14  root     1196: }
                   1197: 
                   1198: // メニューの「デバイス > Push Power Button」UI
                   1199: void
                   1200: WXMainFrame::OnPowerButtonUI(wxUpdateUIEvent& event)
                   1201: {
1.1.1.15! root     1202:        if (gMainApp.Has(VMCap::X68030)) {
        !          1203:                // X68030 の電源ボタンはオルタネート動作なので、
        !          1204:                // チェックで状態を表す。
        !          1205:                event.Check(power->IsPowerPressed());
        !          1206:        } else {
1.1.1.14  root     1207:                // LUNA の電源ボタンはモーメンタリ動作で、電源オフ->オンの機能しかなく
                   1208:                // さらに今の所電源オフ状態はないので、実質無効。
                   1209:                event.Enable(false);
                   1210:        }
                   1211: }
                   1212: 
1.1.1.9   root     1213: // メニューの「デバイス > Push Reset Button」イベント
                   1214: // こっちは本体リセットボタンによるリセット
                   1215: void
                   1216: WXMainFrame::OnResetButton(wxCommandEvent& event)
                   1217: {
1.1.1.15! root     1218:        power->MakeResetHard();
1.1.1.13  root     1219: }
                   1220: 
                   1221: // メニューの「デバイス > Push ABORT(Interrupt) Button」イベント
                   1222: void
                   1223: WXMainFrame::OnNMIButton(wxCommandEvent& event)
                   1224: {
1.1.1.15! root     1225:        auto nmi = GetNMIDevice();
        !          1226:        nmi->PressNMI();
1.1.1.13  root     1227: }
                   1228: 
                   1229: // メニューの「デバイス > Operation > Keyboard Connect」イベント
                   1230: void
                   1231: WXMainFrame::OnKeyboardConnect(wxCommandEvent& event)
                   1232: {
                   1233:        // enable ならチェックを付けようとして呼ばれた
                   1234:        bool enable = event.IsChecked();
                   1235: 
                   1236:        // キーボード接続を設定
1.1.1.15! root     1237:        keyboard->Connect(enable);
1.1.1.13  root     1238: }
                   1239: 
                   1240: // メニューの「デバイス > Operation > Keyboard Connect」UI
                   1241: void
                   1242: WXMainFrame::OnKeyboardConnectUI(wxUpdateUIEvent& event)
                   1243: {
1.1.1.15! root     1244:        event.Check(keyboard->IsConnected());
1.1.1.9   root     1245: }
                   1246: 
1.1       root     1247: // メニューのウィンドウ ID 共通イベント
                   1248: // チェックが入る方なら、ウィンドウを作成して表示。
                   1249: // チェックが消える方なら、ウィンドウを削除。
                   1250: void
                   1251: WXMainFrame::OnWindow(wxCommandEvent& event)
                   1252: {
                   1253:        int id = event.GetId();
                   1254: 
                   1255:        DoWindow(id, event.IsChecked());
                   1256: }
                   1257: 
                   1258: void
                   1259: WXMainFrame::DoWindow(int id, bool enable)
                   1260: {
1.1.1.10  root     1261:        // モニタウィンドウを作成する共通部分。
                   1262:        // id はモニター ID であると同時に、windows[] 配列の添字、さらにこの
                   1263:        // モニタウィンドウの wxWindowID としても使っている
                   1264:        // (WXSubWindow::OnClose() 参照)。
                   1265: #define SetMonitor(id, name)   \
                   1266:        windows[id].reset(new WXMonitorWindow(this, (name), \
1.1.1.13  root     1267:                gMonitorManager->Get(id)))
1.1.1.4   root     1268: 
1.1       root     1269:        if (enable) {
                   1270:                // チェックが入ったのでウィンドウを作成
                   1271:                switch (id) {
1.1.1.10  root     1272:                 case ID_MONITOR_ATC0:
                   1273:                 case ID_MONITOR_ATC1:
                   1274:                 case ID_MONITOR_ATC2:
                   1275:                 case ID_MONITOR_ATC3:
                   1276:                 case ID_MONITOR_ATC4:
                   1277:                 case ID_MONITOR_ATC5:
                   1278:                 case ID_MONITOR_ATC6:
                   1279:                 case ID_MONITOR_ATC7:
                   1280:                 {
                   1281:                        int n = id - ID_MONITOR_ATC0;
                   1282:                        wxString name(string_format("ATC#%d", n));
                   1283:                        if ((n & 1) == 0) {
                   1284:                                name += _("(Data)");
                   1285:                        } else {
                   1286:                                name += _("(Inst)");
                   1287:                        }
                   1288:                        SetMonitor(id, name);
1.1.1.4   root     1289:                        break;
1.1.1.10  root     1290:                 }
                   1291: 
                   1292:                 case ID_MONITOR_BREAKPOINT:
                   1293:                        SetMonitor(id, _("Breakpoint"));
1.1.1.5   root     1294:                        break;
1.1.1.10  root     1295: 
1.1.1.15! root     1296:                 case ID_MONITOR_BT45x:
        !          1297:                        SetMonitor(id, "Bt454/458");
        !          1298:                        break;
        !          1299: 
1.1.1.10  root     1300:                 case ID_MONITOR_CMMU0:
                   1301:                 case ID_MONITOR_CMMU1:
                   1302:                 case ID_MONITOR_CMMU2:
                   1303:                 case ID_MONITOR_CMMU3:
                   1304:                 case ID_MONITOR_CMMU4:
                   1305:                 case ID_MONITOR_CMMU5:
                   1306:                 case ID_MONITOR_CMMU6:
                   1307:                 case ID_MONITOR_CMMU7:
                   1308:                 {
                   1309:                        int n = id - ID_MONITOR_CMMU0;
                   1310:                        wxString name(string_format("CMMU#%d", n));
                   1311:                        if ((n & 1) == 0) {
                   1312:                                name += _("(Data)");
                   1313:                        } else {
                   1314:                                name += _("(Inst)");
                   1315:                        }
                   1316:                        SetMonitor(id, name);
1.1.1.4   root     1317:                        break;
1.1.1.10  root     1318:                 }
                   1319: 
1.1.1.13  root     1320:                 case ID_MONITOR_CRTC:
                   1321:                        SetMonitor(id, "CRTC");
                   1322:                        break;
                   1323: 
1.1.1.10  root     1324:                 case ID_MONITOR_DMAC:
1.1.1.15! root     1325:                        SetMonitor(id, "DMAC (HD63450)");
1.1.1.5   root     1326:                        break;
1.1.1.10  root     1327: 
1.1.1.14  root     1328:                 case ID_MONITOR_FDC:
1.1.1.15! root     1329:                        SetMonitor(id, "FDC (uPD72065B)");
1.1.1.14  root     1330:                        break;
                   1331: 
1.1.1.13  root     1332:                 case ID_MONITOR_HOSTCOM:
                   1333:                        SetMonitor(id, _("Host Serial Port"));
                   1334:                        break;
                   1335: 
                   1336:                 case ID_MONITOR_HOSTNET:
                   1337:                        SetMonitor(id, _("Host Network"));
                   1338:                        break;
                   1339: 
1.1.1.10  root     1340:                 case ID_MONITOR_INTERRUPT:
1.1.1.15! root     1341:                 {
        !          1342:                        wxString name;
        !          1343:                        if (gMainApp.Has(VMCap::M88K)) {
        !          1344:                                // 実際はほぼシステムコントローラなのでややこしい。
        !          1345:                                name = "MPU " + _("Interrupt");
        !          1346:                        } else {
        !          1347:                                name = MPUName() + " " + _("Interrupt");
        !          1348:                        }
        !          1349:                        SetMonitor(id, name);
1.1.1.5   root     1350:                        break;
1.1.1.15! root     1351:                 }
1.1.1.10  root     1352: 
                   1353:                 case ID_MONITOR_KEYBOARD:
                   1354:                        SetMonitor(id, _("Keyboard/Mouse"));
1.1.1.4   root     1355:                        break;
1.1.1.10  root     1356: 
                   1357:                 case ID_MONITOR_LANCE:
1.1.1.15! root     1358:                        SetMonitor(id, "LANCE (AM7990)");
1.1       root     1359:                        break;
1.1.1.10  root     1360: 
                   1361:                 case ID_MONITOR_LCD:
                   1362:                        windows[id].reset(new WXLCDMonitor(this));
1.1.1.4   root     1363:                        break;
1.1.1.10  root     1364: 
1.1.1.13  root     1365:                 case ID_MONITOR_LUNAVC:
                   1366:                        SetMonitor(id, _("Video Control"));
1.1.1.4   root     1367:                        break;
1.1.1.10  root     1368: 
                   1369:                 case ID_MONITOR_MEMDUMP0 ...
1.1.1.15! root     1370:                      ID_MONITOR_MEMDUMP(MAX_MEMDUMP_MONITOR - 1):
        !          1371:                 case ID_MONITOR_XPMEMDUMP0 ...
        !          1372:                      ID_MONITOR_XPMEMDUMP(MAX_XPMEMDUMP_MONITOR - 1):
1.1.1.10  root     1373:                 {
1.1.1.15! root     1374:                        windows[id].reset(new WXMemdumpWindow(this, id));
1.1.1.4   root     1375:                        break;
1.1.1.10  root     1376:                 }
                   1377: 
                   1378:                 case ID_MONITOR_MFP:
1.1.1.15! root     1379:                        SetMonitor(id, "MFP (MC68901)");
1.1.1.4   root     1380:                        break;
1.1.1.10  root     1381: 
                   1382:                 case ID_MONITOR_MK48T02:
1.1.1.15! root     1383:                        SetMonitor(id, "RTC (MK48T02)");
1.1       root     1384:                        break;
1.1.1.10  root     1385: 
                   1386:                 case ID_MONITOR_MPUATC:
1.1.1.15! root     1387:                        SetMonitor(id, "MC68030 ATC");
1.1       root     1388:                        break;
1.1.1.10  root     1389: 
                   1390:                 case ID_MONITOR_MPUREG:
1.1.1.15! root     1391:                 {
        !          1392:                        wxString name = MPUName() + " " + _("Register");
        !          1393:                        SetMonitor(id, name);
        !          1394:                        break;
        !          1395:                 }
        !          1396: 
        !          1397:                 case ID_MONITOR_ROMCONS:
        !          1398:                        SetMonitor(id, _("ROM Console (provisional)"));
1.1.1.7   root     1399:                        break;
1.1.1.10  root     1400: 
1.1.1.15! root     1401:                 case ID_MONITOR_PIO:
        !          1402:                        SetMonitor(id, "PIO0/PIO1");
1.1.1.3   root     1403:                        break;
1.1.1.10  root     1404: 
1.1.1.13  root     1405:                 case ID_MONITOR_RENDERER:
                   1406:                        SetMonitor(id, _("Renderer"));
                   1407:                        break;
                   1408: 
1.1.1.10  root     1409:                 case ID_MONITOR_RTC:
1.1.1.15! root     1410:                        SetMonitor(id, "RTC (RP5C15)");
1.1.1.3   root     1411:                        break;
1.1.1.10  root     1412: 
                   1413:                 case ID_MONITOR_SCC:
1.1.1.15! root     1414:                        SetMonitor(id, "SCC (Z8530)");
1.1.1.3   root     1415:                        break;
1.1.1.10  root     1416: 
                   1417:                 case ID_MONITOR_SCHEDULER:
                   1418:                        SetMonitor(id, _("Scheduler"));
1.1       root     1419:                        break;
1.1.1.10  root     1420: 
1.1.1.11  root     1421:                 case ID_MONITOR_SCSIDEVS:
                   1422:                        SetMonitor(id, _("SCSI Devices"));
                   1423:                        break;
                   1424: 
1.1.1.10  root     1425:                 case ID_MONITOR_SIO:
1.1.1.15! root     1426:                        SetMonitor(id, "SIO (uPD7201)");
1.1.1.4   root     1427:                        break;
1.1.1.10  root     1428: 
                   1429:                 case ID_MONITOR_SPC:
1.1.1.15! root     1430:                        SetMonitor(id, "SPC (MB89352)");
1.1.1.2   root     1431:                        break;
1.1.1.10  root     1432: 
                   1433:                 case ID_MONITOR_SYSCLK:
                   1434:                        SetMonitor(id, _("System Clock"));
1.1       root     1435:                        break;
1.1.1.10  root     1436: 
                   1437:                 case ID_MONITOR_WXHOSTINFO:
                   1438:                        SetMonitor(id, _("Host Information"));
1.1       root     1439:                        break;
1.1.1.10  root     1440: 
1.1.1.15! root     1441:                 case ID_MONITOR_XPREG:
        !          1442:                        SetMonitor(id, "HD647180 " + _("Register"));
        !          1443:                        break;
        !          1444: 
        !          1445:                 case ID_MONITOR_XPINTR:
        !          1446:                        SetMonitor(id, "HD647180 " + _("Interrupt"));
        !          1447:                        break;
        !          1448: 
        !          1449:                 case ID_MONITOR_XPIO:
        !          1450:                        SetMonitor(id, _("HD647180 Internal Devices"));
        !          1451:                        break;
        !          1452: 
1.1.1.10  root     1453:                 case ID_SUBWIN_BRHIST:
1.1.1.15! root     1454:                 {
        !          1455:                        wxString name = MPUName() + " " + _("Branch History");
        !          1456:                        windows[id].reset(new WXScrollMonitorWindow(this, name,
        !          1457:                                gMonitorManager->Get(id)));
1.1.1.4   root     1458:                        break;
1.1.1.15! root     1459:                 }
1.1.1.10  root     1460: 
                   1461:                 case ID_SUBWIN_EXHIST:
1.1.1.15! root     1462:                 {
        !          1463:                        wxString name = MPUName() + " " + _("Exception History");
        !          1464:                        windows[id].reset(new WXScrollMonitorWindow(this, name,
        !          1465:                                gMonitorManager->Get(id)));
1.1.1.5   root     1466:                        break;
1.1.1.15! root     1467:                 }
1.1.1.10  root     1468: 
                   1469:                 case ID_SUBWIN_CACHE0:
                   1470:                 case ID_SUBWIN_CACHE1:
                   1471:                 case ID_SUBWIN_CACHE2:
                   1472:                 case ID_SUBWIN_CACHE3:
                   1473:                 case ID_SUBWIN_CACHE4:
                   1474:                 case ID_SUBWIN_CACHE5:
                   1475:                 case ID_SUBWIN_CACHE6:
                   1476:                 case ID_SUBWIN_CACHE7:
                   1477:                 {
                   1478:                        int n = id - ID_SUBWIN_CACHE0;
                   1479:                        wxString name = _("Cache");
                   1480:                        name += string_format("#%d", n);
                   1481:                        if ((n & 1) == 0) {
                   1482:                                name += _("(Data)");
                   1483:                        } else {
                   1484:                                name += _("(Inst)");
                   1485:                        }
                   1486:                        windows[id].reset(new WXCacheWindow(this, name,
1.1.1.13  root     1487:                                gMonitorManager->Get(id)));
1.1       root     1488:                        break;
1.1.1.10  root     1489:                 }
                   1490: 
1.1.1.15! root     1491:                 case ID_SUBWIN_DIPSW:
        !          1492:                        windows[id].reset(new WXDipswWindow(this));
        !          1493:                        break;
        !          1494: 
1.1.1.10  root     1495:                 case ID_SUBWIN_LCDPANEL:
                   1496:                        windows[id].reset(new WXLCDWindow(this));
1.1       root     1497:                        break;
1.1.1.10  root     1498:                 case ID_SUBWIN_LOG:
                   1499:                        windows[id].reset(new WXLogMonitor(this));
1.1       root     1500:                        break;
1.1.1.13  root     1501:                 case ID_SUBWIN_LOGSETTING:
                   1502:                        windows[id].reset(new WXLogSettingWindow(this));
                   1503:                        break;
1.1.1.14  root     1504: 
1.1.1.13  root     1505:                 case ID_SUBWIN_LUNAFB:
1.1.1.14  root     1506:                 case ID_SUBWIN_TVRAM:
                   1507:                 {
                   1508:                        // 呼び方が違うので名前と ID が違う
                   1509:                        wxString name;
                   1510:                        if (id == ID_SUBWIN_LUNAFB) {
                   1511:                                name = _("Bitmap Plane");
                   1512:                        } else {
                   1513:                                name = _("Text VRAM");
                   1514:                        }
                   1515:                        windows[id].reset(new WXPlaneVRAMWindow(this, name));
                   1516:                        break;
                   1517:                 }
                   1518: 
1.1.1.15! root     1519:                 case ID_SUBWIN_PALETTE:
        !          1520:                 case ID_SUBWIN_TEXTPAL:
        !          1521:                 {
        !          1522:                        // 呼び方が違うので名前と ID が違う
        !          1523:                        wxString name;
        !          1524:                        if (id == ID_SUBWIN_TEXTPAL) {
        !          1525:                                name = _("Text Palette Colormap");
        !          1526:                        } else {
        !          1527:                                name = _("Palette Colormap");
        !          1528:                        }
        !          1529:                        windows[id].reset(new WXPaletteWindow(this, name));
        !          1530:                        break;
        !          1531:                 }
        !          1532: 
1.1.1.14  root     1533:                 case ID_SUBWIN_ROM:
                   1534:                        windows[id].reset(new WXROMWindow(this));
1.1       root     1535:                        break;
1.1.1.10  root     1536: 
                   1537:                 case ID_SUBWIN_SOFTKEY:
                   1538:                        windows[id].reset(new WXSoftKeyWindow(this, gMainApp.GetVMType()));
1.1.1.5   root     1539:                        break;
1.1.1.10  root     1540: 
1.1.1.13  root     1541:                 case ID_SUBWIN_VECTOR:
1.1.1.15! root     1542:                 {
        !          1543:                        wxString name = MPUName() + " " + _("Vector Table");
        !          1544:                        windows[id].reset(new WXScrollMonitorWindow(this, name,
        !          1545:                                gMonitorManager->Get(id)));
1.1.1.13  root     1546:                        break;
1.1.1.15! root     1547:                 }
        !          1548: 
        !          1549:                 case ID_SUBWIN_XPBRHIST:
        !          1550:                 {
        !          1551:                        wxString name = "HD647180 " + _("Branch History");
        !          1552:                        windows[id].reset(new WXScrollMonitorWindow(this, name,
        !          1553:                                gMonitorManager->Get(id)));
        !          1554:                        break;
        !          1555:                 }
        !          1556: 
        !          1557:                 case ID_SUBWIN_XPEXHIST:
        !          1558:                 {
        !          1559:                        wxString name = "HD647180 " + _("Exception History");
        !          1560:                        windows[id].reset(new WXScrollMonitorWindow(this, name,
        !          1561:                                gMonitorManager->Get(id)));
        !          1562:                        break;
        !          1563:                 }
1.1.1.13  root     1564: 
1.1.1.10  root     1565:                 default:
1.1.1.15! root     1566:                        PANIC("'%s' not listed", Monitor::GetIdText(id));
1.1       root     1567:                }
                   1568:                windows[id]->Show();
                   1569:        } else {
                   1570:                // チェックが消えたのでウィンドウを終了
                   1571:                windows[id]->Close();
                   1572:                // (削除自体はこの少し下の DeleteWindow() で行なっている)
                   1573:        }
                   1574: }
                   1575: 
                   1576: // Update UI イベント
                   1577: void
                   1578: WXMainFrame::OnWindowUI(wxUpdateUIEvent& event)
                   1579: {
                   1580:        int id = event.GetId();
                   1581: 
                   1582:        // ウィンドウが存在していればチェックを表示
1.1.1.4   root     1583:        event.Check((bool)windows[id]);
1.1.1.10  root     1584: 
1.1.1.15! root     1585:        if (IS_MONITOR_MEMDUMP(id) || IS_MONITOR_XPMEMDUMP(id)) {
1.1.1.10  root     1586:                // メニューに現在のアドレスを載せる
1.1.1.15! root     1587:                // (ウィンドウの生存期間外にも呼ばれることに注意)
        !          1588:                auto mon = gMonitorManager->Get(id);
        !          1589:                auto *memdump = dynamic_cast<Memdump *>(mon.obj);
        !          1590:                assert(memdump);
        !          1591:                uint32 addr = memdump->GetAddr();
        !          1592: 
        !          1593:                int n;
        !          1594:                wxString text = _("Memory Dump");
        !          1595:                if (IS_MONITOR_XPMEMDUMP(id)) {
        !          1596:                        n = id - ID_MONITOR_XPMEMDUMP0;
        !          1597:                        text += string_format(" &%d: $%05x", n, addr);
        !          1598:                } else {
        !          1599:                        n = id - ID_MONITOR_MEMDUMP0;
        !          1600:                        text += string_format(" &%d: $%08x", n, addr);
        !          1601:                }
        !          1602:                event.SetText(text);
1.1.1.10  root     1603:        }
1.1.1.4   root     1604: }
                   1605: 
                   1606: // バージョンダイアログ
                   1607: void
                   1608: WXMainFrame::OnAbout(wxCommandEvent& event)
                   1609: {
                   1610:        WXVersionDlg dlg(this);
                   1611:        dlg.ShowModal();
1.1       root     1612: }
                   1613: 
1.1.1.14  root     1614: // FD を挿入する。
                   1615: void
                   1616: WXMainFrame::InsertFD(int unit, const std::string& path)
                   1617: {
                   1618:        FDDDevice *fdd = fdd_array[unit];
                   1619:        assert(fdd);
                   1620: 
                   1621:        // VM に依頼
                   1622:        // (エラーが起きれば別途 UI メッセージが飛んでくる)
                   1623:        fdd->LoadDiskUI(path);
                   1624: 
                   1625:        // 次回以降のダイアログのカレントディレクトリをここに更新
                   1626:        auto pos = path.rfind('/');
                   1627:        current_dir = path.substr(0, pos);
                   1628: }
                   1629: 
                   1630: // FD をイジェクトする。
                   1631: void
                   1632: WXMainFrame::EjectFD(int unit, bool force)
                   1633: {
                   1634:        FDDDevice *fdd = fdd_array[unit];
                   1635:        assert(fdd);
                   1636: 
                   1637:        fdd->UnloadDiskUI(force);
                   1638: }
                   1639: 
1.1.1.11  root     1640: // CD/MO を挿入する。
1.1       root     1641: void
1.1.1.11  root     1642: WXMainFrame::InsertCD(int id, const std::string& path)
1.1       root     1643: {
1.1.1.11  root     1644:        SCSIDisk *scsidisk = dynamic_cast<SCSIDisk*>(scsidev[id]);
                   1645:        assert(scsidisk);
1.1       root     1646: 
1.1.1.11  root     1647:        // VM に依頼
                   1648:        // (エラーが起きれば別途 UI メッセージが飛んでくる)
                   1649:        scsidisk->LoadDiskUI(path);
                   1650: 
                   1651:        // 次回以降のダイアログのカレントディレクトリをここに更新
                   1652:        auto pos = path.rfind('/');
                   1653:        current_dir = path.substr(0, pos);
1.1       root     1654: }
                   1655: 
1.1.1.11  root     1656: // CD/MO をイジェクトする。
1.1       root     1657: void
1.1.1.11  root     1658: WXMainFrame::EjectCD(int id, bool force)
1.1       root     1659: {
1.1.1.11  root     1660:        SCSIDisk *scsidisk = dynamic_cast<SCSIDisk*>(scsidev[id]);
                   1661:        assert(scsidisk);
                   1662: 
1.1.1.13  root     1663:        scsidisk->UnloadDiskUI(force);
1.1       root     1664: }
                   1665: 
1.1.1.14  root     1666: // CD/MO/FD の挿入失敗メッセージ。
                   1667: // CD/MO と FD でメッセージが同じなので共用する。
1.1.1.4   root     1668: void
1.1.1.14  root     1669: WXMainFrame::OnInsertFailed(wxCommandEvent& event)
1.1.1.4   root     1670: {
1.1.1.11  root     1671:        ::wxMessageBox(_("Cannot load the image file"));
1.1.1.4   root     1672: }
                   1673: 
1.1.1.11  root     1674: // ウィンドウをリストから削除する
                   1675: // (ウィンドウの Close() から呼ばれる)
1.1.1.4   root     1676: void
1.1.1.11  root     1677: WXMainFrame::DeleteWindow(wxWindow *win)
1.1.1.4   root     1678: {
1.1.1.11  root     1679:        for (int id = 0; id < ID_SUBWIN_MAX; id++) {
                   1680:                if (windows[id].get() == win) {
                   1681:                        windows[id].reset();
                   1682:                        break;
                   1683:                }
                   1684:        }
1.1.1.4   root     1685: }
                   1686: 
1.1.1.15! root     1687: // メイン MPU 名を返す。メニューとタイトルによく出てくるので。
        !          1688: // 88xx0 とか 88200 は別処理。
        !          1689: wxString
        !          1690: WXMainFrame::MPUName() const
        !          1691: {
        !          1692:        if (gMainApp.Has(VMCap::M88K)) {
        !          1693:                return "MC88100";
        !          1694:        } else {
        !          1695:                return "MC68030";
        !          1696:        }
        !          1697: }
        !          1698: 
1.1.1.4   root     1699: // m680x0 ダブルバスフォールト処理
                   1700: void
                   1701: WXMainFrame::OnHaltNotify(wxCommandEvent& event)
                   1702: {
                   1703:        ::wxMessageBox(_("Double bus fault has occurred in VM"),
                   1704:                wxEmptyString,
                   1705:                wxICON_EXCLAMATION);
                   1706: }
                   1707: 
1.1.1.10  root     1708: // 起動時にオープンするサブウィンドウ (-M オプション)
                   1709: /*static*/ std::array<bool, ID_SUBWIN_MAX> WXMainFrame::subwindow_start;
1.1.1.15! root     1710: 
        !          1711: // モニタの更新頻度
        !          1712: /*static*/ int WXMainFrame::monitor_rate;

unix.superglobalmegacorp.com

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