diff --git a/SourceGenWPF/AsmGen/WpfGui/GenAndAsm.xaml b/SourceGenWPF/AsmGen/WpfGui/GenAndAsm.xaml
index e33fe2f..a9ea5c1 100644
--- a/SourceGenWPF/AsmGen/WpfGui/GenAndAsm.xaml
+++ b/SourceGenWPF/AsmGen/WpfGui/GenAndAsm.xaml
@@ -79,7 +79,7 @@ limitations under the License.
+ FontFamily="{StaticResource GeneralMonoFont}" VerticalScrollBarVisibility="Auto">
sample text1
@@ -95,10 +95,8 @@ limitations under the License.
+ FontFamily="{StaticResource GeneralMonoFont}" VerticalScrollBarVisibility="Auto">
sample text2
- a
- b
diff --git a/SourceGenWPF/AsmGen/WpfGui/GenAndAsm.xaml.cs b/SourceGenWPF/AsmGen/WpfGui/GenAndAsm.xaml.cs
index 2f137f3..d5c70ea 100644
--- a/SourceGenWPF/AsmGen/WpfGui/GenAndAsm.xaml.cs
+++ b/SourceGenWPF/AsmGen/WpfGui/GenAndAsm.xaml.cs
@@ -15,6 +15,7 @@
*/
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Text;
@@ -22,6 +23,7 @@ using System.Windows;
using System.Windows.Controls;
using CommonUtil;
+using SourceGenWPF.WpfGui;
namespace SourceGenWPF.AsmGen.WpfGui {
///
@@ -240,8 +242,24 @@ namespace SourceGenWPF.AsmGen.WpfGui {
PopulateAssemblerComboBox(item.AssemblerId.ToString());
}
+ private class GenWorker : WorkProgress.IWorker {
+ IGenerator mGenerator;
+ public List Results { get; private set; }
+
+ public GenWorker(IGenerator gen) {
+ mGenerator = gen;
+ }
+ public object DoWork(BackgroundWorker worker) {
+ worker.ReportProgress(50, "Halfway there!");
+ System.Threading.Thread.Sleep(3000);
+ return mGenerator.GenerateSource(worker);
+ }
+ public void RunWorkerCompleted(object results) {
+ Results = (List)results;
+ }
+ }
+
private void GenerateButton_Click(object sender, RoutedEventArgs e) {
-#if false
IGenerator gen = AssemblerInfo.GetGenerator(mSelectedAssemblerId);
if (gen == null) {
Debug.WriteLine("Unable to get generator for " + mSelectedAssemblerId);
@@ -250,15 +268,15 @@ namespace SourceGenWPF.AsmGen.WpfGui {
gen.Configure(mProject, mWorkDirectory, mBaseFileName,
AssemblerVersionCache.GetVersion(mSelectedAssemblerId), AppSettings.Global);
- GeneratorProgress dlg = new GeneratorProgress(gen);
+ GenWorker gw = new GenWorker(gen);
+ WorkProgress dlg = new WorkProgress(this, gw, false);
dlg.ShowDialog();
- Debug.WriteLine("Dialog returned: " + dlg.DialogResult);
+ //Debug.WriteLine("Dialog returned: " + dlg.DialogResult);
- List pathNames = dlg.Results;
- dlg.Dispose();
+ List pathNames = gw.Results;
if (pathNames == null) {
- // errors already reported
+ // error or cancelation; errors already reported
return;
}
@@ -271,9 +289,6 @@ namespace SourceGenWPF.AsmGen.WpfGui {
previewFileComboBox.SelectedIndex = 0; // should trigger update
UpdateAssemblerControls();
-#else
- Debug.WriteLine("GENERATE");
-#endif
}
private void LoadPreviewFile(string pathName) {
@@ -296,8 +311,22 @@ namespace SourceGenWPF.AsmGen.WpfGui {
}
}
+ private class AsmWorker : WorkProgress.IWorker {
+ IAssembler mAssembler;
+ public AssemblerResults Results { get; private set; }
+
+ public AsmWorker(IAssembler asm) {
+ mAssembler = asm;
+ }
+ public object DoWork(BackgroundWorker worker) {
+ return mAssembler.RunAssembler(worker);
+ }
+ public void RunWorkerCompleted(object results) {
+ Results = (AssemblerResults)results;
+ }
+ }
+
private void RunAssemblerButton_Click(object sender, RoutedEventArgs e) {
-#if false
IAssembler asm = AssemblerInfo.GetAssembler(mSelectedAssemblerId);
if (asm == null) {
Debug.WriteLine("Unable to get assembler for " + mSelectedAssemblerId);
@@ -305,15 +334,17 @@ namespace SourceGenWPF.AsmGen.WpfGui {
}
asm.Configure(mGenerationResults, mWorkDirectory);
- AssemblerProgress dlg = new AssemblerProgress(asm);
+
+ AsmWorker aw = new AsmWorker(asm);
+ WorkProgress dlg = new WorkProgress(this, aw, true);
dlg.ShowDialog();
- Debug.WriteLine("Dialog returned: " + dlg.DialogResult);
- if (dlg.DialogResult != DialogResult.OK) {
- // Cancelled, or failed to even run the assembler.
+ //Debug.WriteLine("Dialog returned: " + dlg.DialogResult);
+ if (dlg.DialogResult != true) {
+ // Canceled, or failed to even run the assembler.
return;
}
- AssemblerResults results = dlg.Results;
+ AssemblerResults results = aw.Results;
if (results == null) {
Debug.WriteLine("Dialog returned OK, but no assembler results found");
Debug.Assert(false);
@@ -328,29 +359,29 @@ namespace SourceGenWPF.AsmGen.WpfGui {
if (results.ExitCode == 0) {
FileInfo fi = new FileInfo(results.OutputPathName);
if (!fi.Exists) {
- MessageBox.Show(this, Properties.Resources.ASM_OUTPUT_NOT_FOUND,
- Properties.Resources.ASM_MISMATCH_CAPTION,
- MessageBoxButtons.OK, MessageBoxIcon.Error);
- sb.Append(Properties.Resources.ASM_MATCH_FAILURE);
+ MessageBox.Show(this, Res.Strings.ASM_OUTPUT_NOT_FOUND,
+ Res.Strings.ASM_MISMATCH_CAPTION,
+ MessageBoxButton.OK, MessageBoxImage.Error);
+ sb.Append(Res.Strings.ASM_MATCH_FAILURE);
} else if (!CommonUtil.FileUtil.CompareBinaryFile(mProject.FileData,
results.OutputPathName, out int offset, out byte fileVal)) {
if (fi.Length != mProject.FileData.Length &&
offset == fi.Length || offset == mProject.FileData.Length) {
// The files matched up to the point where one ended.
- string msg = string.Format(Properties.Resources.ASM_MISMATCH_LENGTH_FMT,
+ string msg = string.Format(Res.Strings.ASM_MISMATCH_LENGTH_FMT,
fi.Length, mProject.FileData.Length);
- MessageBox.Show(this, msg, Properties.Resources.ASM_MISMATCH_CAPTION,
- MessageBoxButtons.OK, MessageBoxIcon.Error);
+ MessageBox.Show(msg, Res.Strings.ASM_MISMATCH_CAPTION,
+ MessageBoxButton.OK, MessageBoxImage.Error);
sb.Append(msg);
} else {
- string msg = string.Format(Properties.Resources.ASM_MISMATCH_DATA_FMT,
+ string msg = string.Format(Res.Strings.ASM_MISMATCH_DATA_FMT,
offset, fileVal, mProject.FileData[offset]);
- MessageBox.Show(this, msg, Properties.Resources.ASM_MISMATCH_CAPTION,
- MessageBoxButtons.OK, MessageBoxIcon.Error);
+ MessageBox.Show(msg, Res.Strings.ASM_MISMATCH_CAPTION,
+ MessageBoxButton.OK, MessageBoxImage.Error);
sb.Append(msg);
}
} else {
- sb.Append(Properties.Resources.ASM_MATCH_SUCCESS);
+ sb.Append(Res.Strings.ASM_MATCH_SUCCESS);
}
}
sb.Append("\r\n\r\n");
@@ -367,10 +398,6 @@ namespace SourceGenWPF.AsmGen.WpfGui {
}
cmdOutputTextBox.Text = sb.ToString();
- cmdOutputTextBox.BackColor = SystemColors.Window;
-#else
- Debug.WriteLine("ASSEMBLE");
-#endif
}
}
}
diff --git a/SourceGenWPF/Res/Strings.xaml b/SourceGenWPF/Res/Strings.xaml
index 31afc2b..0984301 100644
--- a/SourceGenWPF/Res/Strings.xaml
+++ b/SourceGenWPF/Res/Strings.xaml
@@ -20,6 +20,12 @@ limitations under the License.
xmlns:local="clr-namespace:SourceGenWPF.Res">
[latest version]
+ output DOES NOT match data file
+ output matches data file
+ Output Mismatch
+ Assembled output does not match: offset +{0:x6} has value ${1:x2}, expected ${2:x2}.
+ Assembled output does not match: length is {0}, expected {1}.
+ Expected output file wasn't created
Default
Bad format descriptor at +{0:x6}.
Bad format descriptor type
diff --git a/SourceGenWPF/Res/Strings.xaml.cs b/SourceGenWPF/Res/Strings.xaml.cs
index 9b816ff..a23c83d 100644
--- a/SourceGenWPF/Res/Strings.xaml.cs
+++ b/SourceGenWPF/Res/Strings.xaml.cs
@@ -17,9 +17,26 @@ using System;
using System.Windows;
namespace SourceGenWPF.Res {
+ ///
+ /// This is a bridge between the XAML definitions and the C# code that uses the strings.
+ /// FindResource() throws an exception if the resource isn't found, so typos and missing
+ /// resources will cause the app to fail at launch.
+ ///
public static class Strings {
public static string ASM_LATEST_VERSION =
(string)Application.Current.FindResource("str_AsmLatestVersion");
+ public static string ASM_MATCH_FAILURE =
+ (string)Application.Current.FindResource("str_AsmMatchFailure");
+ public static string ASM_MATCH_SUCCESS =
+ (string)Application.Current.FindResource("str_AsmMatchSuccess");
+ public static string ASM_MISMATCH_CAPTION =
+ (string)Application.Current.FindResource("str_AsmMismatchCaption");
+ public static string ASM_MISMATCH_DATA_FMT =
+ (string)Application.Current.FindResource("str_AsmMismatchDataFmt");
+ public static string ASM_MISMATCH_LENGTH_FMT =
+ (string)Application.Current.FindResource("str_AsmMismatchLengthFmt");
+ public static string ASM_OUTPUT_NOT_FOUND =
+ (string)Application.Current.FindResource("str_AsmOutputNotFound");
public static string DEFAULT_VALUE =
(string)Application.Current.FindResource("str_DefaultValue");
public static string ERR_BAD_FD =
diff --git a/SourceGenWPF/SourceGenWPF.csproj b/SourceGenWPF/SourceGenWPF.csproj
index 051146e..d9c3b6f 100644
--- a/SourceGenWPF/SourceGenWPF.csproj
+++ b/SourceGenWPF/SourceGenWPF.csproj
@@ -73,6 +73,9 @@
+
+ WorkProgress.xaml
+
GenAndAsm.xaml
@@ -161,6 +164,10 @@
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
diff --git a/SourceGenWPF/WpfGui/WorkProgress.xaml b/SourceGenWPF/WpfGui/WorkProgress.xaml
new file mode 100644
index 0000000..77d927d
--- /dev/null
+++ b/SourceGenWPF/WpfGui/WorkProgress.xaml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
diff --git a/SourceGenWPF/WpfGui/WorkProgress.xaml.cs b/SourceGenWPF/WpfGui/WorkProgress.xaml.cs
new file mode 100644
index 0000000..94305c4
--- /dev/null
+++ b/SourceGenWPF/WpfGui/WorkProgress.xaml.cs
@@ -0,0 +1,139 @@
+/*
+ * 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.ComponentModel;
+using System.Diagnostics;
+using System.Windows;
+
+namespace SourceGenWPF.WpfGui {
+ ///
+ /// Cancelable progress dialog.
+ ///
+ public partial class WorkProgress : Window {
+ ///
+ /// Task-specific stuff.
+ ///
+ public interface IWorker {
+ ///
+ /// Does the work, executing on a work thread.
+ ///
+ /// BackgroundWorker object reference.
+ /// Results of work.
+ object DoWork(BackgroundWorker worker);
+
+ ///
+ /// Called on successful completion of the work. Executes on main thread.
+ ///
+ /// Results of work.
+ void RunWorkerCompleted(object results);
+ }
+
+ private IWorker mCallbacks;
+
+ private BackgroundWorker mWorker;
+
+
+ public WorkProgress(Window owner, IWorker callbacks, bool indeterminate) {
+ InitializeComponent();
+ Owner = Owner;
+
+ progressBar.IsIndeterminate = indeterminate;
+
+ mCallbacks = callbacks;
+
+ // Create and configure the BackgroundWorker.
+ mWorker = new BackgroundWorker();
+ mWorker.WorkerReportsProgress = true;
+ mWorker.WorkerSupportsCancellation = true;
+ mWorker.DoWork += DoWork;
+ mWorker.ProgressChanged += ProgressChanged;
+ mWorker.RunWorkerCompleted += RunWorkerCompleted;
+ }
+
+ private void Window_Loaded(object sender, RoutedEventArgs e) {
+ mWorker.RunWorkerAsync();
+ }
+
+ private void CancelButton_Click(object sender, RoutedEventArgs e) {
+ mWorker.CancelAsync();
+ cancelButton.IsEnabled = false;
+ }
+
+ private void Window_Closing(object sender, CancelEventArgs e) {
+ // Either we're closing naturally, or the user clicked the 'X' in the window frame.
+ //
+ // Strictly speaking, we should treat this as a cancel request, and set
+ // e.Cancel = true to prevent the form from closing until the worker stops.
+ // However, we don't currently kill runaway processes, which would leave the
+ // user with no way to close the dialog, potentially requiring them to kill the
+ // entire app with unsaved work. Better to abandon the runaway process.
+ //
+ // We call CancelAsync so that the results are discarded should the worker
+ // eventually finish.
+ if (mWorker.IsBusy) {
+ mWorker.CancelAsync();
+ DialogResult = false;
+ }
+ }
+
+ // NOTE: executes on work thread. DO NOT do any UI work here. DO NOT access
+ // the Results property directly.
+ private void DoWork(object sender, DoWorkEventArgs e) {
+ Debug.Assert(sender == mWorker);
+
+ object results = mCallbacks.DoWork(mWorker);
+ if (mWorker.CancellationPending) {
+ e.Cancel = true;
+ } else {
+ e.Result = results;
+ }
+ }
+
+ // Callback that fires when a progress update is made.
+ private void ProgressChanged(object sender, ProgressChangedEventArgs e) {
+ int percent = e.ProgressPercentage;
+ string msg = e.UserState as string;
+
+ Debug.Assert(percent >= 0 && percent <= 100);
+
+ if (!string.IsNullOrEmpty(msg)) {
+ messageText.Text = msg;
+ }
+ progressBar.Value = percent;
+ }
+
+ // Callback that fires when execution completes.
+ private void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
+ if (e.Cancelled) {
+ Debug.WriteLine("CANCELED " + DialogResult);
+ // If the window was closed, the DialogResult will already be set, and WPF
+ // throws a misleading exception ("only after Window is created and shown")
+ // if you try to set the result twice.
+ if (DialogResult == null) {
+ DialogResult = false;
+ }
+ } else if (e.Error != null) {
+ // Unexpected -- shell command execution shouldn't throw exceptions.
+ MessageBox.Show(e.Error.ToString(), Res.Strings.OPERATION_FAILED,
+ MessageBoxButton.OK, MessageBoxImage.Error);
+ DialogResult = false;
+ } else {
+ mCallbacks.RunWorkerCompleted(e.Result);
+ DialogResult = true;
+ }
+ }
+ }
+}