1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Data;
5 using System.Drawing;
6 using System.IO;
7 using System.Linq;
8 using System.Text;
9 using System.Threading.Tasks;
10 using System.Windows.Forms;
11 using Mesen.GUI.Config;
12 using Mesen.GUI.Forms;
13 using Mesen.GUI.Controls;
14 using Be.Windows.Forms;
15 using Mesen.GUI.Debugger.Controls;
16 
17 namespace Mesen.GUI.Debugger
18 {
19 	public partial class frmMemoryViewer : BaseForm
20 	{
21 		private InteropEmu.NotificationListener _notifListener;
22 		private DebugMemoryType _memoryType = DebugMemoryType.CpuMemory;
23 		private DebugWorkspace _previousWorkspace;
24 		private bool _updating = false;
25 		private DateTime _lastUpdate = DateTime.MinValue;
26 		private TabPage _selectedTab;
27 		private bool _formClosed;
28 
frmMemoryViewer()29 		public frmMemoryViewer()
30 		{
31 			InitializeComponent();
32 		}
33 
OnLoad(EventArgs e)34 		protected override void OnLoad(EventArgs e)
35 		{
36 			base.OnLoad(e);
37 
38 			DebugWorkspaceManager.AutoLoadDbgFiles(true);
39 
40 			this._selectedTab = this.tabMain.SelectedTab;
41 
42 			DebugInfo config = ConfigManager.Config.DebugInfo;
43 
44 			this.mnuAutoRefresh.Checked = config.RamAutoRefresh;
45 			this.mnuHighDensityMode.Checked = config.RamHighDensityTextMode;
46 			this.mnuByteEditingMode.Checked = config.RamByteEditingMode;
47 			this.mnuEnablePerByteNavigation.Checked = config.RamEnablePerByteNavigation;
48 			UpdateRefreshSpeedMenu();
49 
50 			this.mnuIgnoreRedundantWrites.Checked = config.RamIgnoreRedundantWrites;
51 			this.UpdateFlags();
52 
53 			this.mnuHighlightCurrentRowColumn.Checked = config.RamHighlightCurrentRowColumn;
54 			this.ctrlHexViewer.HighlightCurrentRowColumn = config.RamHighlightCurrentRowColumn;
55 
56 			this.mnuShowCharacters.Checked = config.RamShowCharacters;
57 			this.mnuShowLabelInfoOnMouseOver.Checked = config.RamShowLabelInfo;
58 
59 			this.ctrlHexViewer.TextZoom = config.RamTextZoom;
60 			this.ctrlHexViewer.BaseFont = new Font(config.RamFontFamily, config.RamFontSize, config.RamFontStyle);
61 
62 			this.ctrlMemoryAccessCounters.BaseFont = new Font(config.RamFontFamily, config.RamFontSize, config.RamFontStyle);
63 			this.ctrlMemoryAccessCounters.TextZoom = config.RamTextZoom;
64 
65 			this.mnuHighlightExecution.Checked = config.RamHighlightExecution;
66 			this.mnuHightlightReads.Checked = config.RamHighlightReads;
67 			this.mnuHighlightWrites.Checked = config.RamHighlightWrites;
68 			this.mnuHideUnusedBytes.Checked = config.RamHideUnusedBytes;
69 			this.mnuHideReadBytes.Checked = config.RamHideReadBytes;
70 			this.mnuHideWrittenBytes.Checked = config.RamHideWrittenBytes;
71 			this.mnuHideExecutedBytes.Checked = config.RamHideExecutedBytes;
72 
73 			this.mnuHighlightLabelledBytes.Checked = config.RamHighlightLabelledBytes;
74 			this.mnuHighlightBreakpoints.Checked = config.RamHighlightBreakpoints;
75 			this.mnuHighlightChrDrawnBytes.Checked = config.RamHighlightChrDrawnBytes;
76 			this.mnuHighlightChrReadBytes.Checked = config.RamHighlightChrReadBytes;
77 			this.mnuHighlightCodeBytes.Checked = config.RamHighlightCodeBytes;
78 			this.mnuHighlightDataBytes.Checked = config.RamHighlightDataBytes;
79 			this.mnuHighlightDmcDataBytes.Checked = config.RamHighlightDmcDataBytes;
80 
81 			this.UpdateFadeOptions();
82 
83 			this.InitTblMappings();
84 
85 			this.ctrlHexViewer.StringViewVisible = mnuShowCharacters.Checked;
86 			this.ctrlHexViewer.MemoryViewer = this;
87 
88 			UpdateImportButton();
89 			InitMemoryTypeDropdown(true);
90 
91 			_notifListener = new InteropEmu.NotificationListener(ConfigManager.Config.DebugInfo.DebugConsoleId);
92 			_notifListener.OnNotification += _notifListener_OnNotification;
93 
94 			this.mnuShowCharacters.CheckedChanged += this.mnuShowCharacters_CheckedChanged;
95 			this.mnuIgnoreRedundantWrites.CheckedChanged += mnuIgnoreRedundantWrites_CheckedChanged;
96 
97 			if(!ConfigManager.Config.DebugInfo.MemoryViewerSize.IsEmpty) {
98 				this.StartPosition = FormStartPosition.Manual;
99 				this.Size = ConfigManager.Config.DebugInfo.MemoryViewerSize;
100 				this.Location = ConfigManager.Config.DebugInfo.MemoryViewerLocation;
101 			}
102 
103 			this.InitShortcuts();
104 		}
105 
OnFormClosing(FormClosingEventArgs e)106 		protected override void OnFormClosing(FormClosingEventArgs e)
107 		{
108 			base.OnFormClosing(e);
109 			UpdateConfig();
110 			ConfigManager.Config.DebugInfo.RamFontFamily = ctrlHexViewer.BaseFont.FontFamily.Name;
111 			ConfigManager.Config.DebugInfo.RamFontStyle = ctrlHexViewer.BaseFont.Style;
112 			ConfigManager.Config.DebugInfo.RamFontSize = ctrlHexViewer.BaseFont.Size;
113 			ConfigManager.Config.DebugInfo.MemoryViewerSize = this.WindowState != FormWindowState.Normal ? this.RestoreBounds.Size : this.Size;
114 			ConfigManager.Config.DebugInfo.MemoryViewerLocation = this.WindowState != FormWindowState.Normal ? this.RestoreBounds.Location : this.Location;
115 			ConfigManager.Config.DebugInfo.RamMemoryType = cboMemoryType.GetEnumValue<DebugMemoryType>();
116 			ConfigManager.ApplyChanges();
117 			DebugWorkspaceManager.SaveWorkspace();
118 
119 			if(this._notifListener != null) {
120 				this._notifListener.Dispose();
121 				this._notifListener = null;
122 			}
123 
124 			_formClosed = true;
125 		}
126 
InitShortcuts()127 		private void InitShortcuts()
128 		{
129 			mnuIncreaseFontSize.InitShortcut(this, nameof(DebuggerShortcutsConfig.IncreaseFontSize));
130 			mnuDecreaseFontSize.InitShortcut(this, nameof(DebuggerShortcutsConfig.DecreaseFontSize));
131 			mnuResetFontSize.InitShortcut(this, nameof(DebuggerShortcutsConfig.ResetFontSize));
132 
133 			mnuImport.InitShortcut(this, nameof(DebuggerShortcutsConfig.MemoryViewer_Import));
134 			mnuExport.InitShortcut(this, nameof(DebuggerShortcutsConfig.MemoryViewer_Export));
135 
136 			mnuRefresh.InitShortcut(this, nameof(DebuggerShortcutsConfig.Refresh));
137 
138 			mnuGoToAll.InitShortcut(this, nameof(DebuggerShortcutsConfig.GoToAll));
139 			mnuGoTo.InitShortcut(this, nameof(DebuggerShortcutsConfig.GoTo));
140 			mnuFind.InitShortcut(this, nameof(DebuggerShortcutsConfig.Find));
141 			mnuFindNext.InitShortcut(this, nameof(DebuggerShortcutsConfig.FindNext));
142 			mnuFindPrev.InitShortcut(this, nameof(DebuggerShortcutsConfig.FindPrev));
143 		}
144 
InitMemoryTypeDropdown(bool forStartup)145 		private void InitMemoryTypeDropdown(bool forStartup)
146 		{
147 			cboMemoryType.SelectedIndexChanged -= this.cboMemoryType_SelectedIndexChanged;
148 
149 			DebugMemoryType originalValue = forStartup ? ConfigManager.Config.DebugInfo.RamMemoryType : cboMemoryType.GetEnumValue<DebugMemoryType>();
150 
151 			cboMemoryType.BeginUpdate();
152 			cboMemoryType.Items.Clear();
153 
154 			cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.CpuMemory));
155 			cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.PpuMemory));
156 			cboMemoryType.Items.Add("-");
157 
158 			if(InteropEmu.DebugGetMemorySize(DebugMemoryType.PrgRom) > 0) {
159 				cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.PrgRom));
160 			}
161 			if(InteropEmu.DebugGetMemorySize(DebugMemoryType.WorkRam) > 0) {
162 				cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.WorkRam));
163 			}
164 			if(InteropEmu.DebugGetMemorySize(DebugMemoryType.SaveRam) > 0) {
165 				cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.SaveRam));
166 			}
167 
168 			if(cboMemoryType.Items.Count > 3) {
169 				cboMemoryType.Items.Add("-");
170 			}
171 
172 			if(InteropEmu.DebugGetMemorySize(DebugMemoryType.ChrRom) > 0) {
173 				cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.ChrRom));
174 			}
175 
176 			if(InteropEmu.DebugGetMemorySize(DebugMemoryType.ChrRam) > 0) {
177 				cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.ChrRam));
178 			}
179 
180 			cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.NametableRam));
181 			cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.PaletteMemory));
182 			cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.SpriteMemory));
183 			cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.SecondarySpriteMemory));
184 
185 			cboMemoryType.SelectedIndex = 0;
186 			cboMemoryType.SetEnumValue(originalValue);
187 			cboMemoryType.SelectedIndexChanged += this.cboMemoryType_SelectedIndexChanged;
188 
189 			cboMemoryType.EndUpdate();
190 			UpdateMemoryType();
191 		}
192 
UpdateFlags()193 		private void UpdateFlags()
194 		{
195 			if(mnuIgnoreRedundantWrites.Checked) {
196 				DebugWorkspaceManager.SetFlags(DebuggerFlags.IgnoreRedundantWrites);
197 			} else {
198 				DebugWorkspaceManager.ClearFlags(DebuggerFlags.IgnoreRedundantWrites);
199 			}
200 		}
201 
ShowAddress(int address, DebugMemoryType memoryType)202 		public void ShowAddress(int address, DebugMemoryType memoryType)
203 		{
204 			if(memoryType == DebugMemoryType.InternalRam) {
205 				//There is no specific "tab" for the internal ram, show it in the cpu memory tab
206 				memoryType = DebugMemoryType.CpuMemory;
207 			}
208 
209 			tabMain.SelectedTab = tpgMemoryViewer;
210 			cboMemoryType.SetEnumValue(memoryType);
211 			ctrlHexViewer.GoToAddress(address);
212 		}
213 
GoToDestination(GoToDestination dest)214 		public void GoToDestination(GoToDestination dest)
215 		{
216 			if(_memoryType == DebugMemoryType.CpuMemory && dest.CpuAddress >= 0) {
217 				this.ShowAddress(dest.CpuAddress, DebugMemoryType.CpuMemory);
218 			} else if(dest.AddressInfo != null) {
219 				this.ShowAddress(dest.AddressInfo.Address, dest.AddressInfo.Type.ToMemoryType());
220 			} else if(dest.Label != null) {
221 				int relAddress = dest.Label.GetRelativeAddress();
222 				if(_memoryType == DebugMemoryType.CpuMemory && relAddress >= 0) {
223 					this.ShowAddress(relAddress, DebugMemoryType.CpuMemory);
224 				} else {
225 					this.ShowAddress((int)dest.Label.Address, dest.Label.AddressType.ToMemoryType());
226 				}
227 			} else if(dest.CpuAddress >= 0) {
228 				this.ShowAddress(dest.CpuAddress, DebugMemoryType.CpuMemory);
229 			}
230 
231 			this.BringToFront();
232 		}
233 
GoToAll()234 		public void GoToAll()
235 		{
236 			using(frmGoToAll frm = new frmGoToAll(true, false)) {
237 				if(frm.ShowDialog() == DialogResult.OK) {
238 					GoToDestination(frm.Destination);
239 				}
240 			}
241 		}
242 
InitTblMappings()243 		private void InitTblMappings()
244 		{
245 			DebugWorkspace workspace = DebugWorkspaceManager.GetWorkspace();
246 			if(workspace.TblMappings != null && workspace.TblMappings.Count > 0) {
247 				var tblDict = TblLoader.ToDictionary(workspace.TblMappings.ToArray());
248 				if(tblDict != null) {
249 					this.ctrlHexViewer.ByteCharConverter = new TblByteCharConverter(tblDict);
250 				}
251 			} else {
252 				this.ctrlHexViewer.ByteCharConverter = null;
253 			}
254 		}
255 
_notifListener_OnNotification(InteropEmu.NotificationEventArgs e)256 		private void _notifListener_OnNotification(InteropEmu.NotificationEventArgs e)
257 		{
258 			switch(e.NotificationType) {
259 				case InteropEmu.ConsoleNotificationType.CodeBreak:
260 					this.BeginInvoke((MethodInvoker)(() => this.RefreshData()));
261 					break;
262 
263 				case InteropEmu.ConsoleNotificationType.GameReset:
264 				case InteropEmu.ConsoleNotificationType.GameLoaded:
265 					this.BeginInvoke((Action)(() => {
266 						if(_formClosed) {
267 							return;
268 						}
269 						this.InitMemoryTypeDropdown(false);
270 						ctrlMemoryAccessCounters.InitMemoryTypeDropdown();
271 					}));
272 					this.UpdateFlags();
273 					break;
274 
275 				case InteropEmu.ConsoleNotificationType.PpuFrameDone:
276 					int refreshDelay = 90;
277 					switch(ConfigManager.Config.DebugInfo.RamAutoRefreshSpeed) {
278 						case RefreshSpeed.Low: refreshDelay= 90; break;
279 						case RefreshSpeed.Normal: refreshDelay = 32; break;
280 						case RefreshSpeed.High: refreshDelay = 16; break;
281 					}
282 
283 					DateTime now = DateTime.Now;
284 					if(!_updating && ConfigManager.Config.DebugInfo.RamAutoRefresh && (now - _lastUpdate).Milliseconds >= refreshDelay) {
285 						_lastUpdate = now;
286 						_updating = true;
287 						this.BeginInvoke((Action)(() => {
288 							this.RefreshData();
289 							_updating = false;
290 						}));
291 					}
292 					break;
293 			}
294 		}
295 
cboMemoryType_SelectedIndexChanged(object sender, EventArgs e)296 		private void cboMemoryType_SelectedIndexChanged(object sender, EventArgs e)
297 		{
298 			UpdateMemoryType();
299 		}
300 
UpdateMemoryType()301 		private void UpdateMemoryType()
302 		{
303 			this._memoryType = this.cboMemoryType.GetEnumValue<DebugMemoryType>();
304 			this.UpdateImportButton();
305 			this.RefreshData();
306 		}
307 
UpdateByteColorProvider()308 		private void UpdateByteColorProvider()
309 		{
310 			switch(this._memoryType) {
311 				case DebugMemoryType.CpuMemory:
312 				case DebugMemoryType.PrgRom:
313 				case DebugMemoryType.WorkRam:
314 				case DebugMemoryType.SaveRam:
315 				case DebugMemoryType.InternalRam:
316 					this.ctrlHexViewer.ByteColorProvider = new ByteColorProvider(
317 						this._memoryType,
318 						mnuHighlightExecution.Checked,
319 						mnuHighlightWrites.Checked,
320 						mnuHightlightReads.Checked,
321 						ConfigManager.Config.DebugInfo.RamFadeSpeed,
322 						mnuHideUnusedBytes.Checked,
323 						mnuHideReadBytes.Checked,
324 						mnuHideWrittenBytes.Checked,
325 						mnuHideExecutedBytes.Checked,
326 						mnuHighlightDmcDataBytes.Checked,
327 						mnuHighlightDataBytes.Checked,
328 						mnuHighlightCodeBytes.Checked,
329 						mnuHighlightLabelledBytes.Checked,
330 						mnuHighlightBreakpoints.Checked
331 					);
332 					break;
333 
334 				case DebugMemoryType.PpuMemory:
335 				case DebugMemoryType.ChrRom:
336 				case DebugMemoryType.ChrRam:
337 				case DebugMemoryType.PaletteMemory:
338 				case DebugMemoryType.NametableRam:
339 					this.ctrlHexViewer.ByteColorProvider = new ChrByteColorProvider(
340 						this._memoryType,
341 						mnuHighlightWrites.Checked,
342 						mnuHightlightReads.Checked,
343 						ConfigManager.Config.DebugInfo.RamFadeSpeed,
344 						mnuHideUnusedBytes.Checked,
345 						mnuHideReadBytes.Checked,
346 						mnuHideWrittenBytes.Checked,
347 						mnuHighlightChrDrawnBytes.Checked,
348 						mnuHighlightChrReadBytes.Checked,
349 						mnuHighlightBreakpoints.Checked
350 					);
351 					break;
352 
353 				default:
354 					this.ctrlHexViewer.ByteColorProvider = null;
355 					break;
356 			}
357 		}
358 
mnuRefresh_Click(object sender, EventArgs e)359 		private void mnuRefresh_Click(object sender, EventArgs e)
360 		{
361 			this.RefreshData();
362 		}
363 
RefreshData()364 		private void RefreshData()
365 		{
366 			if(_formClosed) {
367 				return;
368 			}
369 
370 			if(DebugWorkspaceManager.GetWorkspace() != this._previousWorkspace) {
371 				this.InitTblMappings();
372 				_previousWorkspace = DebugWorkspaceManager.GetWorkspace();
373 			}
374 
375 			if(this.tabMain.SelectedTab == this.tpgAccessCounters) {
376 				this.ctrlMemoryAccessCounters.RefreshData();
377 			} else if(this.tabMain.SelectedTab == this.tpgMemoryViewer) {
378 				this.UpdateByteColorProvider();
379 				this.ctrlHexViewer.RefreshData(_memoryType);
380 			}
381 		}
382 
mnuFind_Click(object sender, EventArgs e)383 		private void mnuFind_Click(object sender, EventArgs e)
384 		{
385 			this.ctrlHexViewer.OpenSearchBox();
386 		}
387 
mnuFindNext_Click(object sender, EventArgs e)388 		private void mnuFindNext_Click(object sender, EventArgs e)
389 		{
390 			this.ctrlHexViewer.FindNext();
391 		}
392 
mnuFindPrev_Click(object sender, EventArgs e)393 		private void mnuFindPrev_Click(object sender, EventArgs e)
394 		{
395 			this.ctrlHexViewer.FindPrevious();
396 		}
397 
mnuGoTo_Click(object sender, EventArgs e)398 		private void mnuGoTo_Click(object sender, EventArgs e)
399 		{
400 			if(_selectedTab == tpgMemoryViewer) {
401 				this.ctrlHexViewer.GoToAddress();
402 			} else if(_selectedTab == tpgAccessCounters) {
403 				this.ctrlMemoryAccessCounters.GoToAddress();
404 			}
405 		}
406 
mnuGoToAll_Click(object sender, EventArgs e)407 		private void mnuGoToAll_Click(object sender, EventArgs e)
408 		{
409 			this.GoToAll();
410 		}
411 
mnuIncreaseFontSize_Click(object sender, EventArgs e)412 		private void mnuIncreaseFontSize_Click(object sender, EventArgs e)
413 		{
414 			this.ctrlHexViewer.TextZoom += 10;
415 			this.ctrlMemoryAccessCounters.TextZoom += 10;
416 			this.UpdateConfig();
417 		}
418 
mnuDecreaseFontSize_Click(object sender, EventArgs e)419 		private void mnuDecreaseFontSize_Click(object sender, EventArgs e)
420 		{
421 			this.ctrlHexViewer.TextZoom -= 10;
422 			this.ctrlMemoryAccessCounters.TextZoom -= 10;
423 			this.UpdateConfig();
424 		}
425 
mnuResetFontSize_Click(object sender, EventArgs e)426 		private void mnuResetFontSize_Click(object sender, EventArgs e)
427 		{
428 			this.ctrlHexViewer.TextZoom = 100;
429 			this.ctrlMemoryAccessCounters.TextZoom = 100;
430 			this.UpdateConfig();
431 		}
432 
mnuClose_Click(object sender, EventArgs e)433 		private void mnuClose_Click(object sender, EventArgs e)
434 		{
435 			this.Close();
436 		}
437 
UpdateConfig()438 		private void UpdateConfig()
439 		{
440 			ConfigManager.Config.DebugInfo.RamAutoRefresh = this.mnuAutoRefresh.Checked;
441 
442 			ConfigManager.Config.DebugInfo.RamIgnoreRedundantWrites = this.mnuIgnoreRedundantWrites.Checked;
443 			ConfigManager.Config.DebugInfo.RamHighlightCurrentRowColumn = this.mnuHighlightCurrentRowColumn.Checked;
444 
445 			ConfigManager.Config.DebugInfo.RamShowCharacters = this.mnuShowCharacters.Checked;
446 			ConfigManager.Config.DebugInfo.RamShowLabelInfo = this.mnuShowLabelInfoOnMouseOver.Checked;
447 
448 			ConfigManager.Config.DebugInfo.RamTextZoom = this.ctrlHexViewer.TextZoom;
449 			ConfigManager.Config.DebugInfo.RamFontFamily = this.ctrlHexViewer.BaseFont.FontFamily.Name;
450 			ConfigManager.Config.DebugInfo.RamFontSize = this.ctrlHexViewer.BaseFont.Size;
451 			ConfigManager.Config.DebugInfo.RamFontStyle = this.ctrlHexViewer.BaseFont.Style;
452 
453 			ConfigManager.Config.DebugInfo.RamHighlightExecution = this.mnuHighlightExecution.Checked;
454 			ConfigManager.Config.DebugInfo.RamHighlightReads = this.mnuHightlightReads.Checked;
455 			ConfigManager.Config.DebugInfo.RamHighlightWrites = this.mnuHighlightWrites.Checked;
456 			ConfigManager.Config.DebugInfo.RamHideUnusedBytes = this.mnuHideUnusedBytes.Checked;
457 			ConfigManager.Config.DebugInfo.RamHideReadBytes = this.mnuHideReadBytes.Checked;
458 			ConfigManager.Config.DebugInfo.RamHideWrittenBytes = this.mnuHideWrittenBytes.Checked;
459 			ConfigManager.Config.DebugInfo.RamHideExecutedBytes = this.mnuHideExecutedBytes.Checked;
460 			ConfigManager.Config.DebugInfo.RamHideExecutedBytes = this.mnuHideExecutedBytes.Checked;
461 
462 			ConfigManager.Config.DebugInfo.RamHighlightBreakpoints = this.mnuHighlightBreakpoints.Checked;
463 			ConfigManager.Config.DebugInfo.RamHighlightLabelledBytes = this.mnuHighlightLabelledBytes.Checked;
464 			ConfigManager.Config.DebugInfo.RamHighlightChrDrawnBytes = this.mnuHighlightChrDrawnBytes.Checked;
465 			ConfigManager.Config.DebugInfo.RamHighlightChrReadBytes = this.mnuHighlightChrReadBytes.Checked;
466 			ConfigManager.Config.DebugInfo.RamHighlightCodeBytes = this.mnuHighlightCodeBytes.Checked;
467 			ConfigManager.Config.DebugInfo.RamHighlightDataBytes = this.mnuHighlightDataBytes.Checked;
468 			ConfigManager.Config.DebugInfo.RamHighlightDmcDataBytes = this.mnuHighlightDmcDataBytes.Checked;
469 
470 			ConfigManager.ApplyChanges();
471 		}
472 
mnuAutoRefresh_Click(object sender, EventArgs e)473 		private void mnuAutoRefresh_Click(object sender, EventArgs e)
474 		{
475 			this.UpdateConfig();
476 		}
477 
UpdateImportButton()478 		private void UpdateImportButton()
479 		{
480 			switch(_memoryType) {
481 				case DebugMemoryType.ChrRam:
482 				case DebugMemoryType.InternalRam:
483 				case DebugMemoryType.PaletteMemory:
484 				case DebugMemoryType.NametableRam:
485 				case DebugMemoryType.SecondarySpriteMemory:
486 				case DebugMemoryType.SpriteMemory:
487 				case DebugMemoryType.WorkRam:
488 				case DebugMemoryType.SaveRam:
489 					mnuImport.Enabled = true;
490 					break;
491 
492 				default:
493 					mnuImport.Enabled = false;
494 					break;
495 			}
496 		}
497 
mnuImport_Click(object sender, EventArgs e)498 		private void mnuImport_Click(object sender, EventArgs e)
499 		{
500 			OpenFileDialog ofd = new OpenFileDialog();
501 			ofd.SetFilter("Memory dump files (*.dmp)|*.dmp|All files (*.*)|*.*");
502 			ofd.InitialDirectory = ConfigManager.DebuggerFolder;
503 			if(ofd.ShowDialog() == DialogResult.OK) {
504 				InteropEmu.DebugSetMemoryState(_memoryType, File.ReadAllBytes(ofd.FileName));
505 				RefreshData();
506 			}
507 		}
508 
mnuExport_Click(object sender, EventArgs e)509 		private void mnuExport_Click(object sender, EventArgs e)
510 		{
511 			SaveFileDialog sfd = new SaveFileDialog();
512 			sfd.SetFilter("Memory dump files (*.dmp)|*.dmp|All files (*.*)|*.*");
513 			sfd.InitialDirectory = ConfigManager.DebuggerFolder;
514 			sfd.FileName = InteropEmu.GetRomInfo().GetRomName() + " - " + cboMemoryType.SelectedItem.ToString() + ".dmp";
515 			if(sfd.ShowDialog() == DialogResult.OK) {
516 				File.WriteAllBytes(sfd.FileName, this.ctrlHexViewer.GetData());
517 			}
518 		}
519 
tabMain_SelectedIndexChanged(object sender, EventArgs e)520 		private void tabMain_SelectedIndexChanged(object sender, EventArgs e)
521 		{
522 			_selectedTab = this.tabMain.SelectedTab;
523 			this.RefreshData();
524 		}
525 
ctrlHexViewer_RequiredWidthChanged(object sender, EventArgs e)526 		private void ctrlHexViewer_RequiredWidthChanged(object sender, EventArgs e)
527 		{
528 			this.Size = new Size(this.ctrlHexViewer.RequiredWidth + 20, this.Height);
529 		}
530 
mnuLoadTblFile_Click(object sender, EventArgs e)531 		private void mnuLoadTblFile_Click(object sender, EventArgs e)
532 		{
533 			OpenFileDialog ofd = new OpenFileDialog();
534 			ofd.SetFilter("TBL files (*.tbl)|*.tbl");
535 			if(ofd.ShowDialog() == DialogResult.OK) {
536 				string[] fileContents = File.ReadAllLines(ofd.FileName);
537 				var tblDict = TblLoader.ToDictionary(fileContents);
538 				if(tblDict == null) {
539 					MessageBox.Show("Could not load TBL file.  The file selected file appears to be invalid.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
540 				} else {
541 					DebugWorkspaceManager.GetWorkspace().TblMappings = new List<string>(fileContents);
542 					this.ctrlHexViewer.ByteCharConverter = new TblByteCharConverter(tblDict);
543 					this.mnuShowCharacters.Checked = true;
544 				}
545 			}
546 		}
547 
mnuResetTblMappings_Click(object sender, EventArgs e)548 		private void mnuResetTblMappings_Click(object sender, EventArgs e)
549 		{
550 			DebugWorkspaceManager.GetWorkspace().TblMappings = null;
551 			this.ctrlHexViewer.ByteCharConverter = null;
552 		}
553 
mnuShowCharacters_CheckedChanged(object sender, EventArgs e)554 		private void mnuShowCharacters_CheckedChanged(object sender, EventArgs e)
555 		{
556 			this.ctrlHexViewer.StringViewVisible = mnuShowCharacters.Checked;
557 			this.UpdateConfig();
558 		}
559 
mnuIgnoreRedundantWrites_CheckedChanged(object sender, EventArgs e)560 		private void mnuIgnoreRedundantWrites_CheckedChanged(object sender, EventArgs e)
561 		{
562 			this.UpdateFlags();
563 			this.UpdateConfig();
564 		}
565 
UpdateFadeOptions()566 		private void UpdateFadeOptions()
567 		{
568 			int fadeSpeed = ConfigManager.Config.DebugInfo.RamFadeSpeed;
569 			mnuFadeSlow.Checked = fadeSpeed == 600;
570 			mnuFadeNormal.Checked = fadeSpeed == 300;
571 			mnuFadeFast.Checked = fadeSpeed == 120;
572 			mnuFadeNever.Checked = fadeSpeed == 0;
573 			mnuCustomFadeSpeed.Checked = !mnuFadeSlow.Checked && !mnuFadeNormal.Checked && !mnuFadeFast.Checked && !mnuFadeSlow.Checked;
574 		}
575 
mnuFadeSpeed_Click(object sender, EventArgs e)576 		private void mnuFadeSpeed_Click(object sender, EventArgs e)
577 		{
578 			if(sender == mnuFadeSlow) {
579 				ConfigManager.Config.DebugInfo.RamFadeSpeed = 600;
580 			} else if(sender == mnuFadeNormal) {
581 				ConfigManager.Config.DebugInfo.RamFadeSpeed = 300;
582 			} else if(sender == mnuFadeFast) {
583 				ConfigManager.Config.DebugInfo.RamFadeSpeed = 120;
584 			} else if(sender == mnuFadeNever) {
585 				ConfigManager.Config.DebugInfo.RamFadeSpeed = 0;
586 			}
587 			ConfigManager.ApplyChanges();
588 			UpdateFadeOptions();
589 		}
590 
mnuCustomFadeSpeed_Click(object sender, EventArgs e)591 		private void mnuCustomFadeSpeed_Click(object sender, EventArgs e)
592 		{
593 			using(frmFadeSpeed frm = new frmFadeSpeed(ConfigManager.Config.DebugInfo.RamFadeSpeed)) {
594 				if(frm.ShowDialog() == DialogResult.OK) {
595 					ConfigManager.Config.DebugInfo.RamFadeSpeed = frm.FadeSpeed;
596 					ConfigManager.ApplyChanges();
597 					UpdateFadeOptions();
598 				}
599 			}
600 		}
601 
mnuColorProviderOptions_Click(object sender, EventArgs e)602 		private void mnuColorProviderOptions_Click(object sender, EventArgs e)
603 		{
604 			this.UpdateConfig();
605 			this.UpdateByteColorProvider();
606 		}
607 
mnuConfigureColors_Click(object sender, EventArgs e)608 		private void mnuConfigureColors_Click(object sender, EventArgs e)
609 		{
610 			using(frmMemoryViewerColors frm = new frmMemoryViewerColors()) {
611 				if(frm.ShowDialog(this, this) == DialogResult.OK) {
612 					this.RefreshData();
613 				}
614 			}
615 		}
616 
617 		private frmCodeTooltip _tooltip = null;
618 		private CodeLabel _lastLabelTooltip = null;
619 		private int _lastLabelArrayOffset = -1;
620 		private int _lastTooltipAddress = -1;
ctrlHexViewer_ByteMouseHover(int address, Point position)621 		private void ctrlHexViewer_ByteMouseHover(int address, Point position)
622 		{
623 			if(address < 0 || !mnuShowLabelInfoOnMouseOver.Checked) {
624 				if(_tooltip != null) {
625 					_tooltip.Close();
626 					_lastLabelTooltip = null;
627 					_lastLabelArrayOffset = -1;
628 					_lastTooltipAddress = -1;
629 				}
630 				return;
631 			}
632 
633 			if(_lastTooltipAddress == address) {
634 				return;
635 			}
636 
637 			_lastTooltipAddress = address;
638 
639 			CodeLabel label = null;
640 			int arrayOffset = 0;
641 			switch(_memoryType) {
642 				case DebugMemoryType.CpuMemory:
643 					AddressTypeInfo info = new AddressTypeInfo();
644 					InteropEmu.DebugGetAbsoluteAddressAndType((UInt32)address, info);
645 					if(info.Address >= 0) {
646 						label = LabelManager.GetLabel((UInt32)info.Address, info.Type);
647 						if(label != null) {
648 							arrayOffset = info.Address - (int)label.Address;
649 						}
650 					}
651 					if(label == null) {
652 						label = LabelManager.GetLabel((UInt32)address, AddressType.Register);
653 					}
654 					break;
655 
656 				case DebugMemoryType.InternalRam:
657 				case DebugMemoryType.WorkRam:
658 				case DebugMemoryType.SaveRam:
659 				case DebugMemoryType.PrgRom:
660 					label = LabelManager.GetLabel((UInt32)address, _memoryType.ToAddressType());
661 					if(label != null) {
662 						arrayOffset = address - (int)label.Address;
663 					}
664 					break;
665 			}
666 
667 			if(label != null) {
668 				if(_lastLabelTooltip != label || _lastLabelArrayOffset != arrayOffset) {
669 					if(_tooltip != null) {
670 						_tooltip.Close();
671 					}
672 
673 					Dictionary<string, string> values = new Dictionary<string, string>();
674 					if(!string.IsNullOrWhiteSpace(label.Label)) {
675 						values["Label"] = label.Label;
676 						if(label.Length > 1) {
677 							values["Label"] += "+" + arrayOffset.ToString();
678 						}
679 					}
680 					values["Address"] = "$" + (label.Address + arrayOffset).ToString("X4");
681 					values["Address Type"] = label.AddressType.ToString();
682 					if(!string.IsNullOrWhiteSpace(label.Comment)) {
683 						values["Comment"] = label.Comment;
684 					}
685 
686 					_tooltip = new frmCodeTooltip(this, values);
687 					_tooltip.FormClosed += (s, evt) => { _tooltip = null; };
688 					_tooltip.SetFormLocation(new Point(position.X, position.Y), ctrlHexViewer);
689 					_lastLabelTooltip = label;
690 					_lastLabelArrayOffset = arrayOffset;
691 				}
692 			} else {
693 				if(_tooltip != null) {
694 					_tooltip.Close();
695 					_lastLabelTooltip = null;
696 					_lastLabelArrayOffset = -1;
697 					_lastTooltipAddress = -1;
698 				}
699 			}
700 		}
701 
mnuAutoRefreshSpeed_Click(object sender, EventArgs e)702 		private void mnuAutoRefreshSpeed_Click(object sender, EventArgs e)
703 		{
704 			if(sender == mnuAutoRefreshLow) {
705 				ConfigManager.Config.DebugInfo.RamAutoRefreshSpeed = RefreshSpeed.Low;
706 			} else if(sender == mnuAutoRefreshNormal) {
707 				ConfigManager.Config.DebugInfo.RamAutoRefreshSpeed = RefreshSpeed.Normal;
708 			} else if(sender == mnuAutoRefreshHigh) {
709 				ConfigManager.Config.DebugInfo.RamAutoRefreshSpeed = RefreshSpeed.High;
710 			}
711 			ConfigManager.ApplyChanges();
712 
713 			UpdateRefreshSpeedMenu();
714 		}
715 
UpdateRefreshSpeedMenu()716 		private void UpdateRefreshSpeedMenu()
717 		{
718 			mnuAutoRefreshLow.Checked = ConfigManager.Config.DebugInfo.RamAutoRefreshSpeed == RefreshSpeed.Low;
719 			mnuAutoRefreshNormal.Checked = ConfigManager.Config.DebugInfo.RamAutoRefreshSpeed == RefreshSpeed.Normal;
720 			mnuAutoRefreshHigh.Checked = ConfigManager.Config.DebugInfo.RamAutoRefreshSpeed == RefreshSpeed.High;
721 		}
722 
mnuHighDensityMode_CheckedChanged(object sender, EventArgs e)723 		private void mnuHighDensityMode_CheckedChanged(object sender, EventArgs e)
724 		{
725 			ConfigManager.Config.DebugInfo.RamHighDensityTextMode = mnuHighDensityMode.Checked;
726 			ConfigManager.ApplyChanges();
727 			ctrlHexViewer.HighDensityMode = ConfigManager.Config.DebugInfo.RamHighDensityTextMode;
728 		}
729 
mnuEnablePerByteNavigation_CheckedChanged(object sender, EventArgs e)730 		private void mnuEnablePerByteNavigation_CheckedChanged(object sender, EventArgs e)
731 		{
732 			ConfigManager.Config.DebugInfo.RamEnablePerByteNavigation = mnuEnablePerByteNavigation.Checked;
733 			ConfigManager.ApplyChanges();
734 			ctrlHexViewer.EnablePerByteNavigation = ConfigManager.Config.DebugInfo.RamEnablePerByteNavigation;
735 		}
736 
mnuSelectFont_Click(object sender, EventArgs e)737 		private void mnuSelectFont_Click(object sender, EventArgs e)
738 		{
739 			ctrlHexViewer.BaseFont = FontDialogHelper.SelectFont(ctrlHexViewer.BaseFont);
740 			ctrlMemoryAccessCounters.BaseFont = ctrlHexViewer.BaseFont;
741 		}
742 
mnuByteEditingMode_CheckedChanged(object sender, EventArgs e)743 		private void mnuByteEditingMode_CheckedChanged(object sender, EventArgs e)
744 		{
745 			ConfigManager.Config.DebugInfo.RamByteEditingMode = mnuByteEditingMode.Checked;
746 			ConfigManager.ApplyChanges();
747 			ctrlHexViewer.ByteEditingMode = ConfigManager.Config.DebugInfo.RamByteEditingMode;
748 		}
749 
mnuHighlightCurrentRowColumn_CheckedChanged(object sender, EventArgs e)750 		private void mnuHighlightCurrentRowColumn_CheckedChanged(object sender, EventArgs e)
751 		{
752 			ctrlHexViewer.HighlightCurrentRowColumn = mnuHighlightCurrentRowColumn.Checked;
753 		}
754 	}
755 }
756