1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-06-30 06:29:32 +00:00

Finish generate/assemble dialog

Added the progress dialog as a relatively generic thing (it was
implemented as a pair of dialogs in the WinForms version, for no
very good reason).  Generation and assembler execution works.
This commit is contained in:
Andy McFadden 2019-06-24 14:41:08 -07:00
parent 985eba804b
commit 8d8112f5c9
7 changed files with 262 additions and 34 deletions

View File

@ -79,7 +79,7 @@ limitations under the License.
</Grid>
<TextBox Grid.Row="1" Name="previewTextBox" IsReadOnly="True" Margin="0,4,0,0"
FontFamily="{StaticResource GeneralMonoFont}">
FontFamily="{StaticResource GeneralMonoFont}" VerticalScrollBarVisibility="Auto">
sample text1
</TextBox>
@ -95,10 +95,8 @@ limitations under the License.
</DockPanel>
<TextBox DockPanel.Dock="Top" Name="cmdOutputTextBox" IsReadOnly="True" Margin="0,4,0,0"
FontFamily="{StaticResource GeneralMonoFont}">
FontFamily="{StaticResource GeneralMonoFont}" VerticalScrollBarVisibility="Auto">
sample text2
a
b
</TextBox>
</DockPanel>

View File

@ -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 {
/// <summary>
@ -240,8 +242,24 @@ namespace SourceGenWPF.AsmGen.WpfGui {
PopulateAssemblerComboBox(item.AssemblerId.ToString());
}
private class GenWorker : WorkProgress.IWorker {
IGenerator mGenerator;
public List<string> 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<string>)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<string> pathNames = dlg.Results;
dlg.Dispose();
List<string> 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
}
}
}

View File

@ -20,6 +20,12 @@ limitations under the License.
xmlns:local="clr-namespace:SourceGenWPF.Res">
<system:String x:Key="str_AsmLatestVersion">[latest version]</system:String>
<system:String x:Key="str_AsmMatchFailure">output DOES NOT match data file</system:String>
<system:String x:Key="str_AsmMatchSuccess">output matches data file</system:String>
<system:String x:Key="str_AsmMismatchCaption">Output Mismatch</system:String>
<system:String x:Key="str_AsmMismatchDataFmt">Assembled output does not match: offset +{0:x6} has value ${1:x2}, expected ${2:x2}.</system:String>
<system:String x:Key="str_AsmMismatchLengthFmt">Assembled output does not match: length is {0}, expected {1}.</system:String>
<system:String x:Key="str_AsmOutputNotFound">Expected output file wasn't created</system:String>
<system:String x:Key="str_DefaultValue">Default</system:String>
<system:String x:Key="str_ErrBadFd">Bad format descriptor at +{0:x6}.</system:String>
<system:String x:Key="str_ErrBadFdFormat">Bad format descriptor type</system:String>

View File

@ -17,9 +17,26 @@ using System;
using System.Windows;
namespace SourceGenWPF.Res {
/// <summary>
/// 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.
/// </summary>
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 =

View File

@ -73,6 +73,9 @@
<Compile Include="AsmGen\IGenerator.cs" />
<Compile Include="AsmGen\LabelLocalizer.cs" />
<Compile Include="AsmGen\StringGather.cs" />
<Compile Include="WpfGui\WorkProgress.xaml.cs">
<DependentUpon>WorkProgress.xaml</DependentUpon>
</Compile>
<Compile Include="AsmGen\WpfGui\GenAndAsm.xaml.cs">
<DependentUpon>GenAndAsm.xaml</DependentUpon>
</Compile>
@ -161,6 +164,10 @@
<Resource Include="Res\Logo.png" />
</ItemGroup>
<ItemGroup>
<Page Include="WpfGui\WorkProgress.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="AsmGen\WpfGui\GenAndAsm.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>

View File

@ -0,0 +1,34 @@
<!--
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.WpfGui.WorkProgress"
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:local="clr-namespace:SourceGenWPF.AsmGen.WpfGui"
mc:Ignorable="d"
Title="Progress"
SizeToContent="WidthAndHeight" ResizeMode="NoResize"
ShowInTaskbar="False" WindowStartupLocation="CenterOwner"
Loaded="Window_Loaded" Closing="Window_Closing">
<StackPanel Margin="8">
<TextBlock Name="messageText" HorizontalAlignment="Left" Text="Preparing..."/>
<ProgressBar Name="progressBar" Width="600" Height="23" Margin="0,8,0,0"/>
<Button Name="cancelButton" Width="75" Margin="0,8,0,0" HorizontalAlignment="Center"
Content="Cancel" Click="CancelButton_Click"/>
</StackPanel>
</Window>

View File

@ -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 {
/// <summary>
/// Cancelable progress dialog.
/// </summary>
public partial class WorkProgress : Window {
/// <summary>
/// Task-specific stuff.
/// </summary>
public interface IWorker {
/// <summary>
/// Does the work, executing on a work thread.
/// </summary>
/// <param name="worker">BackgroundWorker object reference.</param>
/// <returns>Results of work.</returns>
object DoWork(BackgroundWorker worker);
/// <summary>
/// Called on successful completion of the work. Executes on main thread.
/// </summary>
/// <param name="results">Results of work.</param>
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;
}
}
}
}