diff --git a/Gen3Hex/Gen3Hex.csproj b/Gen3Hex/Gen3Hex.csproj index d21e431d..cf2b278f 100644 --- a/Gen3Hex/Gen3Hex.csproj +++ b/Gen3Hex/Gen3Hex.csproj @@ -68,7 +68,14 @@ + + AboutWindow.xaml + + + Designer + MSBuild:Compile + MSBuild:Compile Designer @@ -96,6 +103,7 @@ + \ No newline at end of file diff --git a/Gen3Hex/Model/IFileSystem.cs b/Gen3Hex/Model/IFileSystem.cs index c9890996..8811ac8d 100644 --- a/Gen3Hex/Model/IFileSystem.cs +++ b/Gen3Hex/Model/IFileSystem.cs @@ -1,5 +1,7 @@ namespace HavenSoft.Gen3Hex.Model { public interface IFileSystem { + string CopyText { get; set; } + /// /// Have the filesystem ask the user for a new name for a file. /// If no extensionOptions are provided, the user may specify any extension. diff --git a/Gen3Hex/View/AboutWindow.xaml b/Gen3Hex/View/AboutWindow.xaml new file mode 100644 index 00000000..2ddf7114 --- /dev/null +++ b/Gen3Hex/View/AboutWindow.xaml @@ -0,0 +1,27 @@ + + + + Gen3Hex is a non-profit open-source fan-made tool. + Only use it with legally purchased software. + Pokemon is the property of Nintendo and GameFreak. + Please support the official release. + + + + + + + MIT License + + + Solarized + + + + diff --git a/Gen3Hex/View/AboutWindow.xaml.cs b/Gen3Hex/View/AboutWindow.xaml.cs new file mode 100644 index 00000000..baddc078 --- /dev/null +++ b/Gen3Hex/View/AboutWindow.xaml.cs @@ -0,0 +1,13 @@ +using System.Diagnostics; +using System.Windows.Navigation; + +namespace HavenSoft.Gen3Hex.View { + public partial class AboutWindow { + public AboutWindow() => InitializeComponent(); + + private void Navigate(object sender, RequestNavigateEventArgs e) { + Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri)); + e.Handled = true; + } + } +} diff --git a/Gen3Hex/View/MainWindow.xaml b/Gen3Hex/View/MainWindow.xaml index c23e7424..d532b32c 100644 --- a/Gen3Hex/View/MainWindow.xaml +++ b/Gen3Hex/View/MainWindow.xaml @@ -20,7 +20,9 @@ - + + + true @@ -30,6 +32,7 @@ + @@ -95,6 +98,11 @@ + + + + + @@ -103,6 +111,11 @@ + + + + + diff --git a/Gen3Hex/View/MainWindow.xaml.cs b/Gen3Hex/View/MainWindow.xaml.cs index 17d44e0a..02b6995d 100644 --- a/Gen3Hex/View/MainWindow.xaml.cs +++ b/Gen3Hex/View/MainWindow.xaml.cs @@ -102,6 +102,10 @@ namespace HavenSoft.Gen3Hex.View { if (ViewModel.Count == 0) Close(); } + private void WikiClick(object sender, EventArgs e) => System.Diagnostics.Process.Start("https://github.com/haven1433/gen3hex/wiki"); + private void ReportIssueClick(object sender, EventArgs e) => System.Diagnostics.Process.Start("https://github.com/haven1433/gen3hex/issues"); + private void AboutClick(object sender, EventArgs e) => new AboutWindow().ShowDialog(); + private void GotoBoxVisibilityChanged(object sender, DependencyPropertyChangedEventArgs e) { if (GotoBox.IsVisible) { GotoBox.SelectAll(); diff --git a/Gen3Hex/View/WindowsFileSystem.cs b/Gen3Hex/View/WindowsFileSystem.cs index 4458c579..bfa9e425 100644 --- a/Gen3Hex/View/WindowsFileSystem.cs +++ b/Gen3Hex/View/WindowsFileSystem.cs @@ -6,6 +6,11 @@ using System.Windows; namespace HavenSoft.Gen3Hex.View { public class WindowsFileSystem : IFileSystem { + public string CopyText { + get => Clipboard.ContainsText() ? Clipboard.GetText() : string.Empty; + set => Clipboard.SetText(value); + } + public LoadedFile OpenFile(params string[] extensionOptions) { var dialog = new OpenFileDialog { Filter = CreateFilterFromOptions(extensionOptions) }; var result = dialog.ShowDialog(); diff --git a/Gen3Hex/ViewModel/EditorViewModel.cs b/Gen3Hex/ViewModel/EditorViewModel.cs index 4b3e7c35..3dec8f56 100644 --- a/Gen3Hex/ViewModel/EditorViewModel.cs +++ b/Gen3Hex/ViewModel/EditorViewModel.cs @@ -11,7 +11,7 @@ namespace HavenSoft.Gen3Hex.ViewModel { private readonly IFileSystem fileSystem; private readonly List tabs; - private readonly StubCommand newCommand, open, save, saveAs, saveAll, close, closeAll, undo, redo, back, forward, gotoCommand, showGoto, clearError; + private readonly StubCommand newCommand, open, save, saveAs, saveAll, close, closeAll, undo, redo, cut, copy, paste, delete, back, forward, gotoCommand, showGoto, clearError; private readonly Dictionary, EventHandler> forwardExecuteChangeNotifications; public ICommand New => newCommand; @@ -23,6 +23,10 @@ namespace HavenSoft.Gen3Hex.ViewModel { public ICommand CloseAll => closeAll; public ICommand Undo => undo; public ICommand Redo => redo; + public ICommand Cut => cut; + public ICommand Copy => copy; + public ICommand Paste => paste; + public ICommand Delete => delete; public ICommand Back => back; public ICommand Forward => forward; public ICommand Goto => gotoCommand; @@ -110,6 +114,21 @@ namespace HavenSoft.Gen3Hex.ViewModel { CanExecute = arg => showError, Execute = arg => ErrorMessage = string.Empty, }; + cut = new StubCommand { + CanExecute = arg => SelectedTab?.Copy?.CanExecute(arg) ?? false, + Execute = arg => { + if (SelectedTab != null && SelectedTab.Copy != null && SelectedTab.Clear != null) { + SelectedTab.Copy.Execute(fileSystem); + SelectedTab.Clear.Execute(); + } + } + }; + copy = CreateWrapperForSelected(tab => tab.Copy); + paste = new StubCommand { + CanExecute = arg => SelectedTab is ViewPort, + Execute = arg => (SelectedTab as ViewPort)?.Edit(fileSystem.CopyText), + }; + delete = CreateWrapperForSelected(tab => tab.Clear); save = CreateWrapperForSelected(tab => tab.Save); saveAs = CreateWrapperForSelected(tab => tab.SaveAs); saveAll = CreateWrapperForAll(tab => tab.Save); diff --git a/Gen3Hex/ViewModel/ITabContent.cs b/Gen3Hex/ViewModel/ITabContent.cs index c84eadca..4edabff4 100644 --- a/Gen3Hex/ViewModel/ITabContent.cs +++ b/Gen3Hex/ViewModel/ITabContent.cs @@ -11,6 +11,8 @@ namespace HavenSoft.Gen3Hex.ViewModel { ICommand SaveAs { get; } ICommand Undo { get; } ICommand Redo { get; } + ICommand Copy { get; } + ICommand Clear { get; } ICommand Goto { get; } ICommand Back { get; } ICommand Forward { get; } diff --git a/Gen3Hex/ViewModel/ViewPort.cs b/Gen3Hex/ViewModel/ViewPort.cs index 019475b9..58b4e1dd 100644 --- a/Gen3Hex/ViewModel/ViewPort.cs +++ b/Gen3Hex/ViewModel/ViewPort.cs @@ -8,6 +8,7 @@ using System.ComponentModel; using System.Globalization; using System.IO; using System.Linq; +using System.Text; using System.Windows.Input; namespace HavenSoft.Gen3Hex.ViewModel { @@ -16,6 +17,9 @@ namespace HavenSoft.Gen3Hex.ViewModel { /// public class ViewPort : ViewModelCore, ITabContent, INotifyCollectionChanged { private static readonly NotifyCollectionChangedEventArgs ResetArgs = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset); + private readonly StubCommand + clear = new StubCommand(), + copy = new StubCommand(); private byte[] data; private HexElement[,] currentView; @@ -184,6 +188,9 @@ namespace HavenSoft.Gen3Hex.ViewModel { #endregion + public ICommand Copy => copy; + public ICommand Clear => clear; + public HexElement this[int x, int y] { get { if (x < 0 || x >= Width) return HexElement.Undefined; @@ -214,6 +221,29 @@ namespace HavenSoft.Gen3Hex.ViewModel { history = new ChangeHistory>(RevertChanges); history.PropertyChanged += HistoryPropertyChanged; + clear.CanExecute = arg => true; + clear.Execute = arg => { + var selectionStart = scroll.ViewPointToDataIndex(selection.SelectionStart); + var selectionEnd = scroll.ViewPointToDataIndex(selection.SelectionEnd); + var left = Math.Min(selectionStart, selectionEnd); + var right = Math.Max(selectionStart, selectionEnd); + for (int i = left; i <= right; i++) data[i] = 0xFF; + RefreshBackingData(); + }; + + copy.CanExecute = arg => true; + copy.Execute = arg => { + var selectionStart = scroll.ViewPointToDataIndex(selection.SelectionStart); + var selectionEnd = scroll.ViewPointToDataIndex(selection.SelectionEnd); + var left = Math.Min(selectionStart, selectionEnd); + var right = Math.Max(selectionStart, selectionEnd); + var buffer = new StringBuilder(); + for (int i = left; i <= right; i++) { + buffer.Append(data[i].ToString("X2")); + if (i < right) buffer.Append(" "); + } + ((IFileSystem)arg).CopyText = buffer.ToString(); + }; save = new StubCommand { CanExecute = arg => !history.IsSaved, Execute = arg => SaveExecuted((IFileSystem)arg), diff --git a/Gen3Hex/snorlax.png b/Gen3Hex/snorlax.png new file mode 100644 index 00000000..3492d6ff Binary files /dev/null and b/Gen3Hex/snorlax.png differ diff --git a/HexTests/ViewPortEditTests.cs b/HexTests/ViewPortEditTests.cs index 2446642d..fc139df9 100644 --- a/HexTests/ViewPortEditTests.cs +++ b/HexTests/ViewPortEditTests.cs @@ -252,5 +252,31 @@ namespace HavenSoft.HexTests { Assert.NotEqual(Undefined.Instance, viewPort[0, 4].Format); Assert.Equal(new Point(1, 4), viewPort.SelectionStart); } + + [Fact] + void CanClearData() { + var loadedFile = new LoadedFile("test", new byte[1000]); + var viewPort = new ViewPort(loadedFile) { Width = 5, Height = 5 }; + + viewPort.SelectionStart = new Point(0, 0); + viewPort.SelectionEnd = new Point(3, 3); + viewPort.Clear.Execute(); + + Assert.Equal(0xFF, viewPort[2, 2].Value); + } + + [Fact] + void CanCopyData() { + var loadedFile = new LoadedFile("test", new byte[1000]); + var viewPort = new ViewPort(loadedFile) { Width = 5, Height = 5 }; + var fileSystem = new StubFileSystem(); + + viewPort.Edit("Cafe Babe"); + viewPort.SelectionStart = new Point(0, 0); + viewPort.SelectionEnd = new Point(3, 0); + viewPort.Copy.Execute(fileSystem); + + Assert.Equal("CA FE BA BE", fileSystem.CopyText); + } } }