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