mirror of
https://github.com/fadden/6502bench.git
synced 2025-02-18 08:30:28 +00:00
Implement Show Hex Dump
Because of the way data virtualization works (or doesn't) in WPF, this was a whole lot different from WinForms. What I'm doing is pretty simple, so I avoided the complexity (and quirks) inherent to more complete data virtualization solutions. (All I really want is to not render the entire thing up front.)
This commit is contained in:
parent
b1f84864d6
commit
acfbfcb642
@ -44,6 +44,11 @@ namespace SourceGenWPF {
|
||||
/// NOTE: it may or may not be possible to implement this trivially with an
|
||||
/// ObservableCollection. At an earlier iteration it wasn't, and I'd like to keep this
|
||||
/// around even if it is now possible, in case the pendulum swings back the other way.
|
||||
///
|
||||
/// Additional reading on data virtualization:
|
||||
/// https://www.codeproject.com/Articles/34405/WPF-Data-Virtualization?msg=5635751
|
||||
/// https://web.archive.org/web/20121216034305/http://www.zagstudio.com/blog/498
|
||||
/// https://web.archive.org/web/20121107200359/http://www.zagstudio.com/blog/378
|
||||
/// </remarks>
|
||||
public class DisplayList : IList<DisplayList.FormattedParts>, IList,
|
||||
INotifyCollectionChanged, INotifyPropertyChanged {
|
||||
|
@ -63,6 +63,11 @@ namespace SourceGenWPF {
|
||||
/// </summary>
|
||||
private MainWindow mMainWin;
|
||||
|
||||
/// <summary>
|
||||
/// Hex dump viewer window.
|
||||
/// </summary>
|
||||
private Tools.WpfGui.HexDumpViewer mHexDumpDialog;
|
||||
|
||||
/// <summary>
|
||||
/// List of recently-opened projects.
|
||||
/// </summary>
|
||||
@ -1138,10 +1143,10 @@ namespace SourceGenWPF {
|
||||
if (mShowAnalyzerOutputDialog != null) {
|
||||
mShowAnalyzerOutputDialog.Close();
|
||||
}
|
||||
#endif
|
||||
if (mHexDumpDialog != null) {
|
||||
mHexDumpDialog.Close();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Discard all project state.
|
||||
if (mProject != null) {
|
||||
@ -1371,11 +1376,7 @@ namespace SourceGenWPF {
|
||||
}
|
||||
break;
|
||||
case CodeListColumn.Bytes:
|
||||
#if false
|
||||
if (showHexDumpToolStripMenuItem.Enabled) {
|
||||
ShowHexDump_Click(sender, e);
|
||||
}
|
||||
#endif
|
||||
ShowHexDump();
|
||||
break;
|
||||
case CodeListColumn.Flags:
|
||||
if (CanEditStatusFlags()) {
|
||||
@ -2210,6 +2211,38 @@ namespace SourceGenWPF {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void ShowHexDump() {
|
||||
if (mHexDumpDialog == null) {
|
||||
// Create and show modeless dialog. This one is "always on top" by default,
|
||||
// to allow the user to click around to various points.
|
||||
mHexDumpDialog = new Tools.WpfGui.HexDumpViewer(mMainWin,
|
||||
mProject.FileData, mOutputFormatter);
|
||||
mHexDumpDialog.Closing += (sender, e) => {
|
||||
Debug.WriteLine("Hex dump dialog closed");
|
||||
//showHexDumpToolStripMenuItem.Checked = false;
|
||||
mHexDumpDialog = null;
|
||||
};
|
||||
mHexDumpDialog.Topmost = true;
|
||||
mHexDumpDialog.Show();
|
||||
}
|
||||
|
||||
// Bring it to the front of the window stack. This also transfers focus to the
|
||||
// window.
|
||||
mHexDumpDialog.Activate();
|
||||
|
||||
// Set the dialog's position.
|
||||
if (mMainWin.CodeListView_GetSelectionCount() > 0) {
|
||||
int firstIndex = mMainWin.CodeListView_GetFirstSelectedIndex();
|
||||
int lastIndex = mMainWin.CodeListView_GetLastSelectedIndex();
|
||||
// offsets can be < 0 if they've selected EQU statements
|
||||
int firstOffset = Math.Max(0, CodeLineList[firstIndex].FileOffset);
|
||||
int lastOffset = Math.Max(firstOffset, CodeLineList[lastIndex].FileOffset +
|
||||
CodeLineList[lastIndex].OffsetSpan - 1);
|
||||
mHexDumpDialog.ShowOffsetRange(firstOffset, lastOffset);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanUndo() {
|
||||
return (mProject != null && mProject.CanUndo);
|
||||
}
|
||||
|
@ -78,6 +78,7 @@
|
||||
<Compile Include="Tests\WpfGui\GenTestRunner.xaml.cs">
|
||||
<DependentUpon>GenTestRunner.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Tools\VirtualHexDump.cs" />
|
||||
<Compile Include="WpfGui\AboutBox.xaml.cs">
|
||||
<DependentUpon>AboutBox.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@ -114,6 +115,9 @@
|
||||
<Compile Include="WpfGui\GotoBox.xaml.cs">
|
||||
<DependentUpon>GotoBox.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Tools\WpfGui\HexDumpViewer.xaml.cs">
|
||||
<DependentUpon>HexDumpViewer.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="WpfGui\WorkProgress.xaml.cs">
|
||||
<DependentUpon>WorkProgress.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@ -257,6 +261,10 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Tools\WpfGui\HexDumpViewer.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="WpfGui\WorkProgress.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
@ -23,7 +23,6 @@ limitations under the License.
|
||||
xmlns:local="clr-namespace:SourceGenWPF.Tests.WpfGui"
|
||||
mc:Ignorable="d"
|
||||
Title="Source Generation Test"
|
||||
Icon="/SourceGenWPF;component/Res/SourceGenIcon.ico"
|
||||
Width="640" Height="480" MinWidth="640" MinHeight="480"
|
||||
ShowInTaskbar="False" WindowStartupLocation="CenterOwner"
|
||||
Closing="Window_Closing">
|
||||
|
199
SourceGenWPF/Tools/VirtualHexDump.cs
Normal file
199
SourceGenWPF/Tools/VirtualHexDump.cs
Normal file
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright 2019 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Asm65;
|
||||
|
||||
namespace SourceGenWPF.Tools {
|
||||
/// <summary>
|
||||
/// Generates formatted hex dump lines, and makes them available as a list. The result
|
||||
/// is suitable for use with WPF ItemsSource. Items are generated on demand, providing
|
||||
/// data virtualization.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Doing proper data virtualization in WPF is tricky and annoying. We just render on
|
||||
/// demand and retain the results indefinitely.
|
||||
/// </remarks>
|
||||
public class VirtualHexDump : IList, INotifyCollectionChanged, INotifyPropertyChanged {
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// Data to display. We currently require that the entire file fit in memory,
|
||||
/// which is reasonable because we impose a 2^24 (16MB) limit.
|
||||
/// </summary>
|
||||
private byte[] mData;
|
||||
|
||||
/// <summary>
|
||||
/// Data formatter object.
|
||||
///
|
||||
/// There's currently no way to update this after the dialog is opened, which means
|
||||
/// we won't track changes to hex case preference. I'm okay with that.
|
||||
/// </summary>
|
||||
private Formatter mFormatter;
|
||||
|
||||
private string[] mLines;
|
||||
|
||||
private int mDebugGenLineCount;
|
||||
|
||||
|
||||
public VirtualHexDump(byte[] data, Formatter formatter) {
|
||||
mData = data;
|
||||
mFormatter = formatter;
|
||||
|
||||
Count = (mData.Length + 15) / 16;
|
||||
mLines = new string[Count];
|
||||
mDebugGenLineCount = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Causes all lines to be reformatted. Call this after changing the desired format.
|
||||
/// Generates a collection-reset event, which may cause loss of selection.
|
||||
/// </summary>
|
||||
public void Reformat(Formatter newFormat) {
|
||||
mFormatter = newFormat;
|
||||
|
||||
for (int i = 0; i < mLines.Length; i++) {
|
||||
mLines[i] = null;
|
||||
}
|
||||
OnPropertyChanged(CountString);
|
||||
OnPropertyChanged(IndexerName);
|
||||
OnCollectionReset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Nth line, generating it if it hasn't been yet.
|
||||
/// </summary>
|
||||
private string GetLine(int index) {
|
||||
if (mLines[index] == null) {
|
||||
mLines[index] = mFormatter.FormatHexDump(mData, index * 16);
|
||||
|
||||
//if ((++mDebugGenLineCount % 1000) == 0) {
|
||||
// Debug.WriteLine("DebugGenLineCount: " + mDebugGenLineCount);
|
||||
//}
|
||||
}
|
||||
//Debug.WriteLine("GET LINE " + index + ": " + mLines[index]);
|
||||
return mLines[index];
|
||||
}
|
||||
|
||||
|
||||
#region Property / Collection Changed
|
||||
|
||||
public event NotifyCollectionChangedEventHandler CollectionChanged;
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
private const string CountString = "Count";
|
||||
private const string IndexerName = "Item[]";
|
||||
|
||||
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) {
|
||||
PropertyChanged?.Invoke(this, e);
|
||||
}
|
||||
|
||||
private void OnPropertyChanged(string propertyName) {
|
||||
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e) {
|
||||
CollectionChanged?.Invoke(this, e);
|
||||
}
|
||||
|
||||
private void OnCollectionReset() {
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
||||
}
|
||||
|
||||
#endregion Property / Collection Changed
|
||||
|
||||
#region IList
|
||||
|
||||
public bool IsReadOnly => true;
|
||||
|
||||
public bool IsFixedSize => true;
|
||||
|
||||
public int Count { get; private set; }
|
||||
|
||||
public object SyncRoot => throw new NotImplementedException();
|
||||
|
||||
public bool IsSynchronized => false;
|
||||
|
||||
public object this[int index] {
|
||||
get => GetLine(index);
|
||||
set => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int Add(object value) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Contains(object value) {
|
||||
return (IndexOf(value) >= 0);
|
||||
}
|
||||
|
||||
public void Clear() {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int IndexOf(object value) {
|
||||
//Debug.WriteLine("VHD IndexOf " + value);
|
||||
// This gets called sometimes when the selection changes, because the selection
|
||||
// mechanism tracks objects rather than indices. Fortunately we can convert the
|
||||
// value string to an index by parsing the first six characters.
|
||||
int offset = Convert.ToInt32(((string)value).Substring(0, 6), 16);
|
||||
int index = offset / 16;
|
||||
|
||||
// Either the object at the target location matches, or it doesn't; no need to
|
||||
// search. We'll get requests for nonexistent objects after we reformat the
|
||||
// collection.
|
||||
//
|
||||
// Object equality is what's desired; no need for string comparison
|
||||
if ((object)mLines[index] == value) {
|
||||
return index;
|
||||
}
|
||||
//Debug.WriteLine(" IndexOf not found");
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void Insert(int index, object value) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Remove(object value) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void RemoveAt(int index) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void CopyTo(Array array, int index) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IEnumerator GetEnumerator() {
|
||||
// Use the indexer, rather than mLines's enumerator, to get on-demand string gen.
|
||||
for (int i = 0; i < mLines.Length; i++) {
|
||||
yield return this[i];
|
||||
}
|
||||
}
|
||||
|
||||
#endregion IList
|
||||
}
|
||||
}
|
75
SourceGenWPF/Tools/WpfGui/HexDumpViewer.xaml
Normal file
75
SourceGenWPF/Tools/WpfGui/HexDumpViewer.xaml
Normal file
@ -0,0 +1,75 @@
|
||||
<!--
|
||||
Copyright 2019 faddenSoft
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<Window x:Class="SourceGenWPF.Tools.WpfGui.HexDumpViewer"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:system="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:local="clr-namespace:SourceGenWPF.WpfGui"
|
||||
mc:Ignorable="d"
|
||||
Title="Hex Dump Viewer"
|
||||
Icon="/SourceGenWPF;component/Res/SourceGenIcon.ico"
|
||||
Width="542" Height="600" MinWidth="542" MinHeight="180"
|
||||
ShowInTaskbar="False" WindowStartupLocation="CenterOwner"
|
||||
Loaded="Window_Loaded">
|
||||
|
||||
<Window.Resources>
|
||||
<system:String x:Key="str_PlainAscii">Basic ASCII</system:String>
|
||||
<system:String x:Key="str_HighLowAscii">High/Low ASCII</system:String>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Margin="8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- DataGrid gives us Ctrl+A select-all and Ctrl+C text-copy built in. -->
|
||||
<DataGrid Name="hexDumpData" Grid.Row="0"
|
||||
IsReadOnly="True"
|
||||
ItemsSource="{Binding HexDumpLines}"
|
||||
FontFamily="{StaticResource GeneralMonoFont}"
|
||||
SnapsToDevicePixels="True"
|
||||
GridLinesVisibility="None"
|
||||
AutoGenerateColumns="False"
|
||||
HeadersVisibility="Column"
|
||||
CanUserReorderColumns="False"
|
||||
CanUserSortColumns="False"
|
||||
SelectionMode="Extended"
|
||||
EnableRowVirtualization="True"
|
||||
ScrollViewer.CanContentScroll="True"
|
||||
VerticalScrollBarVisibility="Visible">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F ASCII"
|
||||
Width="491" Binding="{Binding}"/>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<StackPanel Grid.Row="1" Margin="0,5,0,0" Orientation="Horizontal">
|
||||
<TextBlock Text="Character conversion:" Margin="0,3,0,0"/>
|
||||
<ComboBox Name="charConvComboBox" Width="120" Margin="4,0,0,0"
|
||||
ItemsSource="{Binding CharConvItems}" DisplayMemberPath="Name"
|
||||
SelectionChanged="CharConvComboBox_SelectionChanged"/>
|
||||
|
||||
<CheckBox Content="ASCII-only dump" Margin="16,4,0,0" IsChecked="{Binding AsciiOnlyDump}"/>
|
||||
|
||||
<!-- Bind the checkbox directly to the window's Topmost property. -->
|
||||
<CheckBox Content="Always on top" Margin="16,4,0,0" IsChecked="{Binding Path=Topmost}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
221
SourceGenWPF/Tools/WpfGui/HexDumpViewer.xaml.cs
Normal file
221
SourceGenWPF/Tools/WpfGui/HexDumpViewer.xaml.cs
Normal file
@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright 2019 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using Asm65;
|
||||
|
||||
namespace SourceGenWPF.Tools.WpfGui {
|
||||
/// <summary>
|
||||
/// Hex dump viewer.
|
||||
/// </summary>
|
||||
public partial class HexDumpViewer : Window, INotifyPropertyChanged {
|
||||
/// <summary>
|
||||
/// Maximum length of data we will display.
|
||||
/// </summary>
|
||||
public const int MAX_LENGTH = 1 << 24;
|
||||
|
||||
/// <summary>
|
||||
/// ItemsSource for list.
|
||||
/// </summary>
|
||||
public VirtualHexDump HexDumpLines { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Hex formatter.
|
||||
/// </summary>
|
||||
private Formatter mFormatter;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// If true, don't include non-ASCII characters in text area. (Without this we might
|
||||
/// use Unicode bullets or other glyphs for unprintable text.)
|
||||
/// </summary>
|
||||
public bool AsciiOnlyDump {
|
||||
get { return mAsciiOnlyDump; }
|
||||
set {
|
||||
mAsciiOnlyDump = value;
|
||||
OnPropertyChanged();
|
||||
ReplaceFormatter();
|
||||
}
|
||||
}
|
||||
private bool mAsciiOnlyDump;
|
||||
|
||||
// INotifyPropertyChanged implementation
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
private void OnPropertyChanged([CallerMemberName] string propertyName = "") {
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
public enum CharConvMode {
|
||||
Unknown = 0,
|
||||
PlainAscii,
|
||||
HighLowAscii
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Character conversion combo box item.
|
||||
/// </summary>
|
||||
public class CharConvItem {
|
||||
public string Name { get; private set; }
|
||||
public CharConvMode Mode { get; private set; }
|
||||
|
||||
public CharConvItem(string name, CharConvMode mode) {
|
||||
Name = name;
|
||||
Mode = mode;
|
||||
}
|
||||
}
|
||||
public CharConvItem[] CharConvItems { get; private set; }
|
||||
|
||||
|
||||
public HexDumpViewer(Window owner, byte[] data, Formatter formatter) {
|
||||
InitializeComponent();
|
||||
Owner = owner;
|
||||
DataContext = this;
|
||||
|
||||
Debug.Assert(data.Length <= MAX_LENGTH);
|
||||
|
||||
HexDumpLines = new VirtualHexDump(data, formatter);
|
||||
mFormatter = formatter;
|
||||
|
||||
CharConvItems = new CharConvItem[] {
|
||||
new CharConvItem((string)FindResource("str_PlainAscii"),
|
||||
CharConvMode.PlainAscii),
|
||||
new CharConvItem((string)FindResource("str_HighLowAscii"),
|
||||
CharConvMode.HighLowAscii),
|
||||
};
|
||||
}
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e) {
|
||||
// Restore ASCII-only setting.
|
||||
AsciiOnlyDump = AppSettings.Global.GetBool(AppSettings.HEXD_ASCII_ONLY, false);
|
||||
|
||||
// Restore conv mode setting.
|
||||
CharConvMode mode = (CharConvMode)AppSettings.Global.GetEnum(
|
||||
AppSettings.HEXD_CHAR_CONV, typeof(CharConvMode), (int)CharConvMode.PlainAscii);
|
||||
int index = 0;
|
||||
for (int i = 0; i < CharConvItems.Length; i++) {
|
||||
if (CharConvItems[i].Mode == mode) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
charConvComboBox.SelectedIndex = index;
|
||||
}
|
||||
|
||||
//private void Window_Closing(object sender, EventArgs e) {
|
||||
// Debug.WriteLine("Window width: " + ActualWidth);
|
||||
// Debug.WriteLine("Column width: " + hexDumpData.Columns[0].ActualWidth);
|
||||
//}
|
||||
|
||||
private void CharConvComboBox_SelectionChanged(object sender,
|
||||
SelectionChangedEventArgs e) {
|
||||
ReplaceFormatter();
|
||||
}
|
||||
|
||||
private void ReplaceFormatter() {
|
||||
Formatter.FormatConfig config = mFormatter.Config;
|
||||
|
||||
CharConvItem item = (CharConvItem)charConvComboBox.SelectedItem;
|
||||
if (item == null) {
|
||||
// initializing
|
||||
return;
|
||||
}
|
||||
|
||||
switch (item.Mode) {
|
||||
case CharConvMode.PlainAscii:
|
||||
config.mHexDumpCharConvMode = Formatter.FormatConfig.CharConvMode.PlainAscii;
|
||||
break;
|
||||
case CharConvMode.HighLowAscii:
|
||||
config.mHexDumpCharConvMode = Formatter.FormatConfig.CharConvMode.HighLowAscii;
|
||||
break;
|
||||
default:
|
||||
Debug.Assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
config.mHexDumpAsciiOnly = AsciiOnlyDump;
|
||||
|
||||
// Keep app settings up to date.
|
||||
AppSettings.Global.SetBool(AppSettings.HEXD_ASCII_ONLY, mAsciiOnlyDump);
|
||||
AppSettings.Global.SetEnum(AppSettings.HEXD_CHAR_CONV, typeof(CharConvMode),
|
||||
(int)item.Mode);
|
||||
|
||||
mFormatter = new Formatter(config);
|
||||
HexDumpLines.Reformat(mFormatter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the scroll position and selection to show the specified range.
|
||||
/// </summary>
|
||||
/// <param name="startOffset">First offset to show.</param>
|
||||
/// <param name="endOffset">Last offset to show.</param>
|
||||
public void ShowOffsetRange(int startOffset, int endOffset) {
|
||||
Debug.WriteLine("HexDumpViewer: show +" + startOffset.ToString("x6") + " - +" +
|
||||
endOffset.ToString("x6"));
|
||||
int startLine = startOffset / 16;
|
||||
int endLine = endOffset / 16;
|
||||
|
||||
hexDumpData.SelectedItems.Clear();
|
||||
for (int i = startLine; i <= endLine; i++) {
|
||||
hexDumpData.SelectedItems.Add(HexDumpLines[i]);
|
||||
}
|
||||
|
||||
// Make sure it's visible.
|
||||
hexDumpData.ScrollIntoView(HexDumpLines[endLine]);
|
||||
hexDumpData.ScrollIntoView(HexDumpLines[startLine]);
|
||||
}
|
||||
|
||||
#if false // DataGrid provides this automatically
|
||||
/// <summary>
|
||||
/// Generates a string for every selected line, then copies the full thing to the
|
||||
/// clipboard.
|
||||
/// </summary>
|
||||
private void CopySelectionToClipboard() {
|
||||
ListView.SelectedIndexCollection indices = hexDumpListView.SelectedIndices;
|
||||
if (indices.Count == 0) {
|
||||
Debug.WriteLine("Nothing selected");
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to make the initial allocation big enough to hold the full thing.
|
||||
// Each line is currently 73 bytes, plus we throw in a CRLF. Doesn't have to
|
||||
// be exact. With a 16MB max file size we're creating a ~75MB string for the
|
||||
// clipboard, which .NET and Win10-64 seem to be able to handle.
|
||||
StringBuilder sb = new StringBuilder(indices.Count * (73 + 2));
|
||||
|
||||
try {
|
||||
Application.UseWaitCursor = true;
|
||||
Cursor.Current = Cursors.WaitCursor;
|
||||
|
||||
foreach (int index in indices) {
|
||||
mFormatter.FormatHexDump(mData, index * 16, sb);
|
||||
sb.Append("\r\n");
|
||||
}
|
||||
} finally {
|
||||
Application.UseWaitCursor = false;
|
||||
Cursor.Current = Cursors.Arrow;
|
||||
}
|
||||
|
||||
Clipboard.SetText(sb.ToString(), TextDataFormat.Text);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
@ -121,6 +121,7 @@ limitations under the License.
|
||||
<KeyGesture>Ctrl+A</KeyGesture>
|
||||
</RoutedUICommand.InputGestures>
|
||||
</RoutedUICommand>
|
||||
<RoutedUICommand x:Key="ShowHexDumpCmd" Text="Show Hex Dump"/>
|
||||
<RoutedUICommand x:Key="ToggleDataScanCmd" Text="Toggle Data Scan">
|
||||
<RoutedUICommand.InputGestures>
|
||||
<KeyGesture>Ctrl+D</KeyGesture>
|
||||
@ -203,6 +204,8 @@ limitations under the License.
|
||||
<!-- ListView has a built-in Ctrl+A handler; this only fires when codeListView is not in focus -->
|
||||
<CommandBinding Command="{StaticResource SelectAllCmd}"
|
||||
CanExecute="IsProjectOpen" Executed="SelectAllCmd_Executed"/>
|
||||
<CommandBinding Command="{StaticResource ShowHexDumpCmd}"
|
||||
CanExecute="IsProjectOpen" Executed="ShowHexDumpCmd_Executed"/>
|
||||
<CommandBinding Command="{StaticResource ToggleDataScanCmd}"
|
||||
CanExecute="IsProjectOpen" Executed="ToggleDataScanCmd_Executed"/>
|
||||
<CommandBinding Command="{StaticResource UndoCmd}"
|
||||
@ -266,7 +269,7 @@ limitations under the License.
|
||||
<MenuItem Header="Format As Word"/> <!-- Ctrl+W -->
|
||||
<MenuItem Header="Delete Note/Long Comment"/> <!-- Del -->
|
||||
<Separator/>
|
||||
<MenuItem Header="Show Hex Dump"/>
|
||||
<MenuItem Command="{StaticResource ShowHexDumpCmd}"/>
|
||||
</MenuItem>
|
||||
<MenuItem Header="_Tools">
|
||||
<MenuItem Header="Hex Dump..."/>
|
||||
|
@ -935,6 +935,23 @@ namespace SourceGenWPF.WpfGui {
|
||||
mMainCtrl.EditProjectProperties();
|
||||
}
|
||||
|
||||
private void RecentProjectCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
|
||||
int recentIndex;
|
||||
if (e.Parameter is int) {
|
||||
recentIndex = (int)e.Parameter;
|
||||
} else if (e.Parameter is string) {
|
||||
recentIndex = int.Parse((string)e.Parameter);
|
||||
} else {
|
||||
throw new Exception("Bad parameter: " + e.Parameter);
|
||||
}
|
||||
if (recentIndex < 0 || recentIndex >= MainController.MAX_RECENT_PROJECTS) {
|
||||
throw new Exception("Bad parameter: " + e.Parameter);
|
||||
}
|
||||
|
||||
Debug.WriteLine("Recent project #" + recentIndex);
|
||||
mMainCtrl.OpenRecentProject(recentIndex);
|
||||
}
|
||||
|
||||
private void RemoveHintsCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
|
||||
Debug.WriteLine("remove hints");
|
||||
mMainCtrl.MarkAsType(CodeAnalysis.TypeHint.NoHint, false);
|
||||
@ -970,21 +987,8 @@ namespace SourceGenWPF.WpfGui {
|
||||
Debug.WriteLine("Select All cmd: " + (DateTime.Now - start).TotalMilliseconds + " ms");
|
||||
}
|
||||
|
||||
private void RecentProjectCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
|
||||
int recentIndex;
|
||||
if (e.Parameter is int) {
|
||||
recentIndex = (int)e.Parameter;
|
||||
} else if (e.Parameter is string) {
|
||||
recentIndex = int.Parse((string)e.Parameter);
|
||||
} else {
|
||||
throw new Exception("Bad parameter: " + e.Parameter);
|
||||
}
|
||||
if (recentIndex < 0 || recentIndex >= MainController.MAX_RECENT_PROJECTS) {
|
||||
throw new Exception("Bad parameter: " + e.Parameter);
|
||||
}
|
||||
|
||||
Debug.WriteLine("Recent project #" + recentIndex);
|
||||
mMainCtrl.OpenRecentProject(recentIndex);
|
||||
private void ShowHexDumpCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
|
||||
mMainCtrl.ShowHexDump();
|
||||
}
|
||||
|
||||
private void ToggleDataScanCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user