mirror of
https://github.com/fadden/6502bench.git
synced 2024-11-12 06:06:12 +00:00
5d9b9753e8
We now generate GIF images for visualizations and add inline references to them in the HTML output. Images are scaled using the HTML img properties. This works well on some browsers, but others insist on "smooth" scaling that blurs out the pixels. This may require a workaround. An extra blank line is now added above visualizations. This helps keep the image and data visually grouped. The Apple II bitmap test project was updated to have a visualization set with multiple images at the top of the file.
364 lines
13 KiB
C#
364 lines
13 KiB
C#
/*
|
|
* 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.IO;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
|
|
using CommonUtil;
|
|
using Microsoft.Win32;
|
|
|
|
namespace SourceGen.WpfGui {
|
|
/// <summary>
|
|
/// Export selection dialog.
|
|
/// </summary>
|
|
public partial class Export : Window, INotifyPropertyChanged {
|
|
/// <summary>
|
|
/// Indicates which type of file the user wants to generate.
|
|
/// </summary>
|
|
public enum GenerateFileType {
|
|
Unknown = 0,
|
|
Text,
|
|
Html
|
|
}
|
|
|
|
/// <summary>
|
|
/// Result: type of file to generate.
|
|
/// </summary>
|
|
public GenerateFileType GenType { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Result: full pathname of output file.
|
|
/// </summary>
|
|
public string PathName { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Result: flags indicating which of the optional columns should be shown.
|
|
/// </summary>
|
|
public Exporter.ActiveColumnFlags ColFlags { get; private set; }
|
|
|
|
private bool mIncludeNotes;
|
|
public bool IncludeNotes {
|
|
get { return mIncludeNotes; }
|
|
set { mIncludeNotes = value; OnPropertyChanged(); }
|
|
}
|
|
|
|
private bool mShowOffset;
|
|
public bool ShowOffset {
|
|
get { return mShowOffset; }
|
|
set { mShowOffset = value; OnPropertyChanged(); }
|
|
}
|
|
|
|
private bool mShowAddress;
|
|
public bool ShowAddress {
|
|
get { return mShowAddress; }
|
|
set { mShowAddress = value; OnPropertyChanged(); }
|
|
}
|
|
|
|
private bool mShowBytes;
|
|
public bool ShowBytes {
|
|
get { return mShowBytes; }
|
|
set { mShowBytes = value; OnPropertyChanged(); }
|
|
}
|
|
|
|
private bool mShowFlags;
|
|
public bool ShowFlags {
|
|
get { return mShowFlags; }
|
|
set { mShowFlags = value; OnPropertyChanged(); }
|
|
}
|
|
|
|
private bool mShowAttrs;
|
|
public bool ShowAttr {
|
|
get { return mShowAttrs; }
|
|
set { mShowAttrs = value; OnPropertyChanged(); }
|
|
}
|
|
|
|
private bool mSelectionOnly;
|
|
public bool SelectionOnly {
|
|
get { return mSelectionOnly; }
|
|
set { mSelectionOnly = value; OnPropertyChanged(); }
|
|
}
|
|
|
|
private bool mLongLabelNewLine;
|
|
public bool LongLabelNewLine {
|
|
get { return mLongLabelNewLine; }
|
|
set { mLongLabelNewLine = value; OnPropertyChanged(); }
|
|
}
|
|
|
|
//
|
|
// Numeric input fields, bound directly to TextBox.Text. These rely on a TextChanged
|
|
// field to update the IsValid flag, because the "set" method is only called when the
|
|
// field contains a valid integer.
|
|
//
|
|
private int mAsmLabelColWidth;
|
|
public int AsmLabelColWidth {
|
|
get { return mAsmLabelColWidth; }
|
|
set {
|
|
if (mAsmLabelColWidth != value) {
|
|
mAsmLabelColWidth = value;
|
|
OnPropertyChanged();
|
|
}
|
|
}
|
|
}
|
|
private int mAsmOpcodeColWidth;
|
|
public int AsmOpcodeColWidth {
|
|
get { return mAsmOpcodeColWidth; }
|
|
set {
|
|
if (mAsmOpcodeColWidth != value) {
|
|
mAsmOpcodeColWidth = value;
|
|
OnPropertyChanged();
|
|
}
|
|
}
|
|
}
|
|
private int mAsmOperandColWidth;
|
|
public int AsmOperandColWidth {
|
|
get { return mAsmOperandColWidth; }
|
|
set {
|
|
if (mAsmOperandColWidth != value) {
|
|
mAsmOperandColWidth = value;
|
|
OnPropertyChanged();
|
|
}
|
|
}
|
|
}
|
|
private int mAsmCommentColWidth;
|
|
public int AsmCommentColWidth {
|
|
get { return mAsmCommentColWidth; }
|
|
set {
|
|
if (mAsmCommentColWidth != value) {
|
|
mAsmCommentColWidth = value;
|
|
OnPropertyChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool mTextModePlain;
|
|
public bool TextModePlain {
|
|
get { return mTextModePlain; }
|
|
set { mTextModePlain = value; OnPropertyChanged(); }
|
|
}
|
|
|
|
private bool mTextModeCsv;
|
|
public bool TextModeCsv {
|
|
get { return mTextModeCsv; }
|
|
set { mTextModeCsv = value; OnPropertyChanged(); }
|
|
}
|
|
|
|
private bool mOverwriteCss;
|
|
public bool OverwriteCss {
|
|
get { return mOverwriteCss; }
|
|
set { mOverwriteCss = value; OnPropertyChanged(); }
|
|
}
|
|
|
|
private bool mGenerateImageFiles;
|
|
public bool GenerateImageFiles {
|
|
get { return mGenerateImageFiles; }
|
|
set { mGenerateImageFiles = value; OnPropertyChanged(); }
|
|
}
|
|
|
|
private enum TextMode {
|
|
Unknown = 0,
|
|
PlainText,
|
|
Csv
|
|
}
|
|
|
|
/// <summary>
|
|
/// Valid flag, used to enable the "generate" buttons.
|
|
/// </summary>
|
|
public bool IsValid {
|
|
get { return mIsValid; }
|
|
set { mIsValid = value; OnPropertyChanged(); }
|
|
}
|
|
private bool mIsValid;
|
|
|
|
// INotifyPropertyChanged implementation
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
private void OnPropertyChanged([CallerMemberName] string propertyName = "") {
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Filename of project file.
|
|
/// </summary>
|
|
string mProjectFileName;
|
|
|
|
|
|
public Export(Window owner, string projectFileName) {
|
|
InitializeComponent();
|
|
Owner = owner;
|
|
DataContext = this;
|
|
|
|
mProjectFileName = projectFileName;
|
|
}
|
|
|
|
private void Window_Loaded(object sender, RoutedEventArgs e) {
|
|
IncludeNotes = AppSettings.Global.GetBool(AppSettings.EXPORT_INCLUDE_NOTES, false);
|
|
ShowOffset = AppSettings.Global.GetBool(AppSettings.EXPORT_SHOW_OFFSET, false);
|
|
ShowAddress = AppSettings.Global.GetBool(AppSettings.EXPORT_SHOW_ADDR, false);
|
|
ShowBytes = AppSettings.Global.GetBool(AppSettings.EXPORT_SHOW_BYTES, false);
|
|
ShowFlags = AppSettings.Global.GetBool(AppSettings.EXPORT_SHOW_FLAGS, false);
|
|
ShowAttr = AppSettings.Global.GetBool(AppSettings.EXPORT_SHOW_ATTR, false);
|
|
SelectionOnly = AppSettings.Global.GetBool(AppSettings.EXPORT_SELECTION_ONLY, false);
|
|
LongLabelNewLine =
|
|
AppSettings.Global.GetBool(AppSettings.EXPORT_LONG_LABEL_NEW_LINE, false);
|
|
GenerateImageFiles =
|
|
AppSettings.Global.GetBool(AppSettings.EXPORT_GENERATE_IMAGE_FILES, true);
|
|
|
|
int[] colWidths = new int[] { 9, 8, 11, 72 }; // 100-col output
|
|
string colStr = AppSettings.Global.GetString(AppSettings.EXPORT_COL_WIDTHS, null);
|
|
try {
|
|
if (!string.IsNullOrEmpty(colStr)) {
|
|
colWidths = TextUtil.DeserializeIntArray(colStr);
|
|
if (colWidths.Length != 4) {
|
|
throw new InvalidOperationException("Bad length " + colWidths.Length);
|
|
}
|
|
}
|
|
} finally {
|
|
AsmLabelColWidth = colWidths[0];
|
|
AsmOpcodeColWidth = colWidths[1];
|
|
AsmOperandColWidth = colWidths[2];
|
|
AsmCommentColWidth = colWidths[3];
|
|
}
|
|
|
|
TextMode mode = (TextMode)AppSettings.Global.GetEnum(AppSettings.EXPORT_TEXT_MODE,
|
|
typeof(TextMode), (int)TextMode.PlainText);
|
|
if (mode == TextMode.PlainText) {
|
|
TextModePlain = true;
|
|
} else {
|
|
TextModeCsv = true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Saves the settings to the global settings object.
|
|
/// </summary>
|
|
private void SaveSettings() {
|
|
AppSettings.Global.SetBool(AppSettings.EXPORT_INCLUDE_NOTES, IncludeNotes);
|
|
AppSettings.Global.SetBool(AppSettings.EXPORT_SHOW_OFFSET, ShowOffset);
|
|
AppSettings.Global.SetBool(AppSettings.EXPORT_SHOW_ADDR, ShowAddress);
|
|
AppSettings.Global.SetBool(AppSettings.EXPORT_SHOW_BYTES, ShowBytes);
|
|
AppSettings.Global.SetBool(AppSettings.EXPORT_SHOW_FLAGS, ShowFlags);
|
|
AppSettings.Global.SetBool(AppSettings.EXPORT_SHOW_ATTR, ShowAttr);
|
|
AppSettings.Global.SetBool(AppSettings.EXPORT_SELECTION_ONLY, SelectionOnly);
|
|
AppSettings.Global.SetBool(AppSettings.EXPORT_LONG_LABEL_NEW_LINE, LongLabelNewLine);
|
|
AppSettings.Global.SetBool(AppSettings.EXPORT_GENERATE_IMAGE_FILES,GenerateImageFiles);
|
|
int[] colWidths = new int[] {
|
|
AsmLabelColWidth, AsmOpcodeColWidth, AsmOperandColWidth, AsmCommentColWidth
|
|
};
|
|
string cereal = TextUtil.SerializeIntArray(colWidths);
|
|
AppSettings.Global.SetString(AppSettings.EXPORT_COL_WIDTHS, cereal);
|
|
// OverwriteCss is not saved, since there's generally no reason to replace it.
|
|
// Forcing the user to check it every time is essentially the same as popping
|
|
// up an "are you sure you want to overwrite" dialog, but less annoying for the
|
|
// common case.
|
|
|
|
TextMode mode;
|
|
if (TextModePlain) {
|
|
mode = TextMode.PlainText;
|
|
} else {
|
|
mode = TextMode.Csv;
|
|
}
|
|
AppSettings.Global.SetEnum(AppSettings.EXPORT_TEXT_MODE, typeof(TextMode), (int)mode);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the state of the UI.
|
|
/// </summary>
|
|
private void UpdateControls() {
|
|
bool isValid = true;
|
|
|
|
isValid &= !Validation.GetHasError(asmLabelColWidthTextBox);
|
|
isValid &= !Validation.GetHasError(asmOpcodeColWidthTextBox);
|
|
isValid &= !Validation.GetHasError(asmOperandColWidthTextBox);
|
|
isValid &= !Validation.GetHasError(asmCommentColWidthTextBox);
|
|
|
|
IsValid = isValid;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called whenever something is typed in one of the column width entry boxes.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// We need this because we're using validated int fields rather than strings. The
|
|
/// "set" call doesn't fire if the user types garbage.
|
|
/// </remarks>
|
|
private void AsmColWidthTextBox_TextChanged(object sender, TextChangedEventArgs e) {
|
|
UpdateControls();
|
|
}
|
|
|
|
private void GenerateHtmlButton_Click(object sender, RoutedEventArgs e) {
|
|
GenType = GenerateFileType.Html;
|
|
Finish(Res.Strings.FILE_FILTER_HTML, ".html");
|
|
}
|
|
|
|
private void GenerateTextButton_Click(object sender, RoutedEventArgs e) {
|
|
GenType = GenerateFileType.Text;
|
|
if (TextModeCsv) {
|
|
Finish(Res.Strings.FILE_FILTER_CSV, ".csv");
|
|
} else {
|
|
Finish(Res.Strings.FILE_FILTER_TEXT, ".txt");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handles a click on one of the "generate" buttons.
|
|
/// </summary>
|
|
private void Finish(string fileFilter, string fileExt) {
|
|
Debug.Assert(mProjectFileName == Path.GetFileName(mProjectFileName));
|
|
string initialName = Path.GetFileNameWithoutExtension(mProjectFileName) + fileExt;
|
|
if (GenType == GenerateFileType.Html) {
|
|
// Can't link to a file with an unescaped '#' -- the browser will think
|
|
// it's an anchor.
|
|
initialName = initialName.Replace('#', '_');
|
|
}
|
|
|
|
SaveFileDialog fileDlg = new SaveFileDialog() {
|
|
Filter = fileFilter + "|" + Res.Strings.FILE_FILTER_ALL,
|
|
FilterIndex = 1,
|
|
ValidateNames = true,
|
|
AddExtension = true, // doesn't add extension if non-ext file exists
|
|
FileName = initialName
|
|
};
|
|
if (fileDlg.ShowDialog() != true) {
|
|
return;
|
|
}
|
|
PathName = Path.GetFullPath(fileDlg.FileName);
|
|
|
|
ColFlags = Exporter.ActiveColumnFlags.None;
|
|
if (ShowOffset) {
|
|
ColFlags |= Exporter.ActiveColumnFlags.Offset;
|
|
}
|
|
if (ShowAddress) {
|
|
ColFlags |= Exporter.ActiveColumnFlags.Address;
|
|
}
|
|
if (ShowBytes) {
|
|
ColFlags |= Exporter.ActiveColumnFlags.Bytes;
|
|
}
|
|
if (ShowFlags) {
|
|
ColFlags |= Exporter.ActiveColumnFlags.Flags;
|
|
}
|
|
if (ShowAttr) {
|
|
ColFlags |= Exporter.ActiveColumnFlags.Attr;
|
|
}
|
|
|
|
SaveSettings();
|
|
DialogResult = true;
|
|
}
|
|
}
|
|
}
|