diff --git a/SourceGenWPF/AsmGen/AssemblerInfo.cs b/SourceGenWPF/AsmGen/AssemblerInfo.cs
index 6904195..40e5ea9 100644
--- a/SourceGenWPF/AsmGen/AssemblerInfo.cs
+++ b/SourceGenWPF/AsmGen/AssemblerInfo.cs
@@ -26,7 +26,8 @@ namespace SourceGenWPF.AsmGen {
///
public class AssemblerInfo {
///
- /// Enumeration of supported assemblers. Alphabetical order looks nicest.
+ /// Enumeration of supported assemblers. Sorted alphabetically by human-readable name
+ /// looks nicest.
///
public enum Id {
Unknown = 0,
diff --git a/SourceGenWPF/Res/Strings.xaml b/SourceGenWPF/Res/Strings.xaml
index 1fdc950..af863c9 100644
--- a/SourceGenWPF/Res/Strings.xaml
+++ b/SourceGenWPF/Res/Strings.xaml
@@ -75,6 +75,7 @@ limitations under the License.
The file is {0:N0} bytes long, but the project expected {1:N0}.
The file has CRC {0}, but the project expected {1}.
Failed
+ (none)
Failed while preparing the plugin directory {0}
Failed Preparing Plugin Directory
Executing assembler...
diff --git a/SourceGenWPF/Res/Strings.xaml.cs b/SourceGenWPF/Res/Strings.xaml.cs
index faa57c2..69ee952 100644
--- a/SourceGenWPF/Res/Strings.xaml.cs
+++ b/SourceGenWPF/Res/Strings.xaml.cs
@@ -135,6 +135,8 @@ namespace SourceGenWPF.Res {
(string)Application.Current.FindResource("str_OpenDataWrongLengthFmt");
public static string OPERATION_FAILED =
(string)Application.Current.FindResource("str_OperationFailed");
+ public static string PARENTHETICAL_NONE =
+ (string)Application.Current.FindResource("str_ParentheticalNone");
public static string PLUGIN_DIR_FAIL_FMT =
(string)Application.Current.FindResource("str_PluginDirFailFmt");
public static string PLUGIN_DIR_FAIL_CAPTION =
diff --git a/SourceGenWPF/WpfGui/EditAppSettings.xaml b/SourceGenWPF/WpfGui/EditAppSettings.xaml
index a448595..782fb9c 100644
--- a/SourceGenWPF/WpfGui/EditAppSettings.xaml
+++ b/SourceGenWPF/WpfGui/EditAppSettings.xaml
@@ -147,34 +147,49 @@ limitations under the License.
-
+
- C:\something
+ Margin="8,0,0,8" Click="AsmExeBrowseButton_Click"/>
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
diff --git a/SourceGenWPF/WpfGui/EditAppSettings.xaml.cs b/SourceGenWPF/WpfGui/EditAppSettings.xaml.cs
index 96d7b50..5defc9d 100644
--- a/SourceGenWPF/WpfGui/EditAppSettings.xaml.cs
+++ b/SourceGenWPF/WpfGui/EditAppSettings.xaml.cs
@@ -14,12 +14,15 @@
* limitations under the License.
*/
using System;
+using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
+using System.Windows.Input;
+using Microsoft.Win32;
using CommonUtil;
@@ -50,7 +53,8 @@ namespace SourceGenWPF.WpfGui {
private AppSettings mSettings;
///
- /// Dirty flag, set when anything in mSettings changes.
+ /// Dirty flag, set when anything in mSettings changes. Determines whether or not
+ /// the Apply button is enabled.
///
public bool IsDirty {
get { return mIsDirty; }
@@ -62,7 +66,7 @@ namespace SourceGenWPF.WpfGui {
private bool mIsDirty;
///
- /// Tab page enumeration. Numbers must match page indices in designer.
+ /// Tab page enumeration.
///
public enum Tab {
Unknown = -1,
@@ -82,9 +86,11 @@ namespace SourceGenWPF.WpfGui {
///
private AssemblerInfo.Id mInitialAsmId;
+ public List AssemblerList { get; private set; }
+
+ // INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
-
private void OnPropertyChanged([CallerMemberName] string propertyName = "") {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
@@ -144,11 +150,18 @@ namespace SourceGenWPF.WpfGui {
new TextBoxPropertyMap(strDciTextBox, "StrDci"),
new TextBoxPropertyMap(strDciHiTextBox, "StrDciHi"),
};
+#endif
- ConfigureComboBox(asmConfigComboBox);
- ConfigureComboBox(displayFmtQuickComboBox);
- ConfigureComboBox(pseudoOpQuickComboBox);
+ // Create an assembler list for the assembler-config combo box and the two
+ // "quick set" combo boxes.
+ AssemblerList = new List();
+ IEnumerator iter = AssemblerInfo.GetInfoEnumerator();
+ while (iter.MoveNext()) {
+ AssemblerList.Add(iter.Current);
+ }
+ // Can't set the selected item yet.
+#if false
expressionStyleComboBox.DisplayMember = "Name";
foreach (ExpressionStyleItem esi in sExpStyleItems) {
expressionStyleComboBox.Items.Add(esi);
@@ -157,19 +170,10 @@ namespace SourceGenWPF.WpfGui {
}
private void Window_Loaded(object sender, RoutedEventArgs e) {
- PrepCodeView();
+ Loaded_CodeView();
+ Loaded_AsmConfig();
#if false
- // Assemblers.
- PopulateAsmConfigItems();
- showAsmIdentCheckBox.Checked =
- mSettings.GetBool(AppSettings.SRCGEN_ADD_IDENT_COMMENT, false);
- disableLabelLocalizationCheckBox.Checked =
- mSettings.GetBool(AppSettings.SRCGEN_DISABLE_LABEL_LOCALIZATION, false);
- longLabelNewLineCheckBox.Checked =
- mSettings.GetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, false);
- showCycleCountsCheckBox.Checked =
- mSettings.GetBool(AppSettings.SRCGEN_SHOW_CYCLE_COUNTS, false);
// Pseudo ops.
string opStrCereal = mSettings.GetString(AppSettings.FMT_PSEUDO_OP_NAMES, null);
@@ -241,7 +245,7 @@ namespace SourceGenWPF.WpfGui {
#region Code View
- private void PrepCodeView() {
+ private void Loaded_CodeView() {
// Column widths. We called CaptureColumnWidths() during init, so this
// should always be a valid serialized string.
string widthStr = mSettings.GetString(AppSettings.CDLV_COL_WIDTHS, null);
@@ -444,21 +448,203 @@ namespace SourceGenWPF.WpfGui {
#region Asm Config
- ///
- /// Holds an item for the assembler-selection combox box.
- ///
- private class AsmComboItem {
- // Enumerated ID.
- public AssemblerInfo.Id AssemblerId { get; private set; }
-
- // Human-readable name for display.
- public string Name { get; private set; }
-
- public AsmComboItem(AssemblerInfo info) {
- AssemblerId = info.AssemblerId;
- Name = info.Name;
+ private bool mShowCycleCounts;
+ public bool ShowCycleCounts {
+ get { return mShowCycleCounts; }
+ set {
+ mShowCycleCounts = value;
+ OnPropertyChanged();
+ mSettings.SetBool(AppSettings.SRCGEN_SHOW_CYCLE_COUNTS, value);
+ IsDirty = true;
}
}
+ private bool mLongLabelNewLine;
+ public bool LongLabelNewLine {
+ get { return mLongLabelNewLine; }
+ set {
+ mLongLabelNewLine = value;
+ OnPropertyChanged();
+ mSettings.SetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, value);
+ IsDirty = true;
+ }
+ }
+ private bool mAddIdentComment;
+ public bool AddIdentComment {
+ get { return mAddIdentComment; }
+ set {
+ mAddIdentComment = value;
+ OnPropertyChanged();
+ mSettings.SetBool(AppSettings.SRCGEN_ADD_IDENT_COMMENT, value);
+ IsDirty = true;
+ }
+ }
+ private bool mDisableLabelLocalization;
+ public bool DisableLabelLocalization {
+ get { return mDisableLabelLocalization; }
+ set {
+ mDisableLabelLocalization = value;
+ OnPropertyChanged();
+ mSettings.SetBool(AppSettings.SRCGEN_DISABLE_LABEL_LOCALIZATION, value);
+ IsDirty = true;
+ }
+ }
+
+ private void Loaded_AsmConfig() {
+ asmConfigComboBox.SelectedItem = AssemblerInfo.GetAssemblerInfo(mInitialAsmId);
+ if (asmConfigComboBox.SelectedIndex < 0) {
+ Debug.Assert(mInitialAsmId == AssemblerInfo.Id.Unknown);
+ asmConfigComboBox.SelectedIndex = 0;
+ }
+
+ ShowCycleCounts =
+ mSettings.GetBool(AppSettings.SRCGEN_SHOW_CYCLE_COUNTS, false);
+ LongLabelNewLine =
+ mSettings.GetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, false);
+ AddIdentComment =
+ mSettings.GetBool(AppSettings.SRCGEN_ADD_IDENT_COMMENT, false);
+ DisableLabelLocalization =
+ mSettings.GetBool(AppSettings.SRCGEN_DISABLE_LABEL_LOCALIZATION, false);
+ }
+
+ ///
+ /// Populates the UI elements from the asm config item in the settings. If that doesn't
+ /// exist, use the default config.
+ ///
+ private void PopulateAsmConfigItems() {
+ AssemblerInfo info = (AssemblerInfo)asmConfigComboBox.SelectedItem;
+
+ AssemblerConfig config = AssemblerConfig.GetConfig(mSettings, info.AssemblerId);
+ if (config == null) {
+ AsmGen.IAssembler asm = AssemblerInfo.GetAssembler(info.AssemblerId);
+ config = asm.GetDefaultConfig();
+ }
+
+ asmExePathTextBox.Text = config.ExecutablePath;
+ asmLabelColWidthTextBox.Text = config.ColumnWidths[0].ToString();
+ asmOpcodeColWidthTextBox.Text = config.ColumnWidths[1].ToString();
+ asmOperandColWidthTextBox.Text = config.ColumnWidths[2].ToString();
+ asmCommentColWidthTextBox.Text = config.ColumnWidths[3].ToString();
+ }
+
+ private void AsmConfigComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) {
+ // They're switching to a different asm config. Changing the boxes will cause
+ // the dirty flag to be raised, which isn't right, so we save/restore it.
+ bool oldDirty = IsDirty;
+ PopulateAsmConfigItems();
+ IsDirty = oldDirty;
+ }
+
+ ///
+ /// Checks whether the character typed into a column width entry field is allowed.
+ /// This is only useful for screening the character set, not the field contents.
+ ///
+ ///
+ /// This just screens the character. Doesn't handle selection operations like pasting.
+ /// Also, doesn't fire when you hit the space bar. This is only slightly better than
+ /// useless, but since we don't otherwise give an indication of wrongness it's nice
+ /// to have.
+ ///
+ /// Another approach is to bind Text to an integer property. This enables the validation
+ /// mechanism, which puts a red box around the field when it contains bad things, but
+ /// only after focus leaves the field.
+ ///
+ /// See also https://stackoverflow.com/q/1268552/294248
+ ///
+ private void CheckWidthInput(object sender, TextCompositionEventArgs e) {
+ // Set e.Handled to true if the character is invalid.
+ char ch = e.Text[0];
+ e.Handled = (ch < '0' || ch > '9');
+ }
+
+ ///
+ /// Updates the assembler config settings whenever one of the text fields is edited.
+ ///
+ ///
+ /// This fires 4x every time the combo box selection changes, as the new fields are
+ /// populated. That should work out correctly.
+ ///
+ private void AsmLabelColWidthTextBox_TextChanged(object sender, TextChangedEventArgs e) {
+ AssemblerInfo asm = (AssemblerInfo)asmConfigComboBox.SelectedItem;
+ AssemblerConfig.SetConfig(mSettings, asm.AssemblerId, GetAsmConfigFromUi());
+ IsDirty = true;
+ }
+
+ ///
+ /// Extracts the asm configuration items (exe path, column widths) from the UI.
+ ///
+ ///
+ private AssemblerConfig GetAsmConfigFromUi() {
+ const int MIN_WIDTH = 1;
+ const int MAX_WIDTH = 200;
+
+
+ int[] widths = new int[4];
+ for (int i = 0; i < widths.Length; i++) {
+ widths[i] = MIN_WIDTH;
+ }
+
+ int result;
+ if (int.TryParse(asmLabelColWidthTextBox.Text, out result) && result >= MIN_WIDTH &&
+ result <= MAX_WIDTH) {
+ widths[0] = result;
+ }
+ if (int.TryParse(asmOpcodeColWidthTextBox.Text, out result) && result >= MIN_WIDTH &&
+ result <= MAX_WIDTH) {
+ widths[1] = result;
+ }
+ if (int.TryParse(asmOperandColWidthTextBox.Text, out result) && result >= MIN_WIDTH &&
+ result <= MAX_WIDTH) {
+ widths[2] = result;
+ }
+ if (int.TryParse(asmCommentColWidthTextBox.Text, out result) && result >= MIN_WIDTH &&
+ result <= MAX_WIDTH) {
+ widths[3] = result;
+ }
+
+ return new AssemblerConfig(asmExePathTextBox.Text, widths);
+ }
+
+ private void AsmExeBrowseButton_Click(object sender, RoutedEventArgs e) {
+ AssemblerInfo asmInfo = (AssemblerInfo)asmConfigComboBox.SelectedItem;
+
+ // Figure out what we're looking for. For example, cc65 needs "cl65".
+ AsmGen.IAssembler asm = AssemblerInfo.GetAssembler(asmInfo.AssemblerId);
+ asm.GetExeIdentifiers(out string humanName, out string exeName);
+
+ // Ask the user to find it.
+ string pathName = BrowseForExecutable(humanName, exeName);
+ if (pathName != null) {
+ asmExePathTextBox.Text = pathName;
+ AssemblerConfig.SetConfig(mSettings, asmInfo.AssemblerId, GetAsmConfigFromUi());
+ IsDirty = true;
+ }
+
+ }
+
+ ///
+ /// Creates a file dialog to search for a specific executable.
+ ///
+ /// Human-readable filter string for UI.
+ /// Filename of executable.
+ /// Path of executable, or null if dialog was canceled.
+ private string BrowseForExecutable(string prefix, string name) {
+ string pathName = null;
+
+ if (Environment.OSVersion.Platform == PlatformID.Win32NT) {
+ name += ".exe";
+ }
+
+ OpenFileDialog dlg = new OpenFileDialog() {
+ FileName = name,
+ Filter = prefix + "|" + name,
+ RestoreDirectory = true
+ };
+ if (dlg.ShowDialog() == true) {
+ pathName = dlg.FileName;
+ }
+
+ return pathName;
+ }
#endregion AsmConfig
diff --git a/SourceGenWPF/WpfGui/MainWindow.xaml.cs b/SourceGenWPF/WpfGui/MainWindow.xaml.cs
index 1b7c3e5..aea65a2 100644
--- a/SourceGenWPF/WpfGui/MainWindow.xaml.cs
+++ b/SourceGenWPF/WpfGui/MainWindow.xaml.cs
@@ -917,7 +917,7 @@ namespace SourceGenWPF.WpfGui {
Debug.WriteLine("COUNT is " + mMainCtrl.RecentProjectPaths.Count);
if (mMainCtrl.RecentProjectPaths.Count == 0) {
MenuItem mi = new MenuItem();
- mi.Header = "(none)";
+ mi.Header = Res.Strings.PARENTHETICAL_NONE;
recents.Items.Add(mi);
} else {
for (int i = 0; i < mMainCtrl.RecentProjectPaths.Count; i++) {