diff --git a/CommonWPF/CommonWPF.csproj b/CommonWPF/CommonWPF.csproj
index 9882231..d00b625 100644
--- a/CommonWPF/CommonWPF.csproj
+++ b/CommonWPF/CommonWPF.csproj
@@ -63,6 +63,7 @@
Settings.settings
True
+
ResXFileCodeGenerator
diff --git a/CommonWPF/WPFExtensions.cs b/CommonWPF/WPFExtensions.cs
index 31db020..4f3a15a 100644
--- a/CommonWPF/WPFExtensions.cs
+++ b/CommonWPF/WPFExtensions.cs
@@ -36,8 +36,8 @@ namespace CommonWPF {
/// From https://social.msdn.microsoft.com/Forums/vstudio/en-US/7d0626cb-67e8-4a09-a01e-8e56ee7411b2/gridviewcolumheader-radiobuttons?forum=wpf
///
///
- ///
- ///
+ /// Start point.
+ /// Object of appropriate type, or null if not found.
public static T GetVisualChild(this Visual referenceVisual) where T : Visual {
Visual child = null;
for (Int32 i = 0; i < VisualTreeHelper.GetChildrenCount(referenceVisual); i++) {
diff --git a/CommonWPF/WindowPlacement.cs b/CommonWPF/WindowPlacement.cs
new file mode 100644
index 0000000..25ccc88
--- /dev/null
+++ b/CommonWPF/WindowPlacement.cs
@@ -0,0 +1,126 @@
+/*
+ * This comes from "David Rickard's Tech Blog", posted by RandomEngy on March 8 2010:
+ * https://blogs.msdn.microsoft.com/davidrickard/2010/03/08/saving-window-size-and-location-in-wpf-and-winforms/
+ *
+ * Saving and restoring a window's size and position can be tricky when there are multiple
+ * displays involved. This uses the Win32 system functions to do the job properly and
+ * consistently. (In theory.)
+ *
+ * The code works for WinForms (save on FormClosing, restore on Load, using the native handle
+ * from the Handle property) and WPF (use the Window extension methods in Closing and
+ * SourceInitialized). Besides convenience, it has the added benefit of being able to
+ * capture the non-maximized values for a maximized window.
+ */
+
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Windows;
+using System.Windows.Interop;
+using System.Xml;
+using System.Xml.Serialization;
+
+namespace CommonWPF {
+ // RECT structure required by WINDOWPLACEMENT structure
+ [Serializable]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RECT {
+ public int Left;
+ public int Top;
+ public int Right;
+ public int Bottom;
+
+ public RECT(int left, int top, int right, int bottom) {
+ this.Left = left;
+ this.Top = top;
+ this.Right = right;
+ this.Bottom = bottom;
+ }
+ }
+
+ // POINT structure required by WINDOWPLACEMENT structure
+ [Serializable]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct POINT {
+ public int X;
+ public int Y;
+
+ public POINT(int x, int y) {
+ this.X = x;
+ this.Y = y;
+ }
+ }
+
+ // WINDOWPLACEMENT stores the position, size, and state of a window
+ [Serializable]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct WINDOWPLACEMENT {
+ public int length;
+ public int flags;
+ public int showCmd;
+ public POINT minPosition;
+ public POINT maxPosition;
+ public RECT normalPosition;
+ }
+
+ public static class WindowPlacement {
+ private static Encoding encoding = new UTF8Encoding();
+ private static XmlSerializer serializer = new XmlSerializer(typeof(WINDOWPLACEMENT));
+
+ [DllImport("user32.dll")]
+ private static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl);
+
+ [DllImport("user32.dll")]
+ private static extern bool GetWindowPlacement(IntPtr hWnd, out WINDOWPLACEMENT lpwndpl);
+
+ private const int SW_SHOWNORMAL = 1;
+ private const int SW_SHOWMINIMIZED = 2;
+
+ public static void SetPlacement(IntPtr windowHandle, string placementXml) {
+ if (string.IsNullOrEmpty(placementXml)) {
+ return;
+ }
+
+ WINDOWPLACEMENT placement;
+ byte[] xmlBytes = encoding.GetBytes(placementXml);
+
+ try {
+ using (MemoryStream memoryStream = new MemoryStream(xmlBytes)) {
+ placement = (WINDOWPLACEMENT)serializer.Deserialize(memoryStream);
+ }
+
+ placement.length = Marshal.SizeOf(typeof(WINDOWPLACEMENT));
+ placement.flags = 0;
+ placement.showCmd = (placement.showCmd == SW_SHOWMINIMIZED ? SW_SHOWNORMAL : placement.showCmd);
+ SetWindowPlacement(windowHandle, ref placement);
+ } catch (InvalidOperationException) {
+ // Parsing placement XML failed. Fail silently.
+ }
+ }
+
+ public static string GetPlacement(IntPtr windowHandle) {
+ WINDOWPLACEMENT placement = new WINDOWPLACEMENT();
+ GetWindowPlacement(windowHandle, out placement);
+
+ using (MemoryStream memoryStream = new MemoryStream()) {
+ using (XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8)) {
+ serializer.Serialize(xmlTextWriter, placement);
+ byte[] xmlBytes = memoryStream.ToArray();
+ return encoding.GetString(xmlBytes);
+ }
+ }
+ }
+
+ //
+ // Extension methods for WPF.
+ //
+
+ public static string GetPlacement(this Window window) {
+ return GetPlacement(new WindowInteropHelper(window).Handle);
+ }
+ public static void SetPlacement(this Window window, string placementXml) {
+ SetPlacement(new WindowInteropHelper(window).Handle, placementXml);
+ }
+ }
+}
diff --git a/SourceGenWPF/AppSettings.cs b/SourceGenWPF/AppSettings.cs
index d30aa68..087aedf 100644
--- a/SourceGenWPF/AppSettings.cs
+++ b/SourceGenWPF/AppSettings.cs
@@ -37,15 +37,11 @@ namespace SourceGenWPF {
// makes it easy to find all uses.
// Main window.
- public const string MAIN_WINDOW_WIDTH = "main-window-width";
- public const string MAIN_WINDOW_HEIGHT = "main-window-height";
- public const string MAIN_WINDOW_LOC_X = "main-window-loc-x";
- public const string MAIN_WINDOW_LOC_Y = "main-window-loc-y";
- public const string MAIN_WINDOW_MAXIMIZED = "main-window-maximized";
+ public const string MAIN_WINDOW_PLACEMENT = "main-window-placement";
public const string MAIN_LEFT_PANEL_WIDTH = "main-left-panel-width";
public const string MAIN_RIGHT_PANEL_WIDTH = "main-right-panel-width";
- public const string MAIN_LEFT_SIDE_SPLITTER_DIST = "main-left-side-splitter-dist";
- public const string MAIN_RIGHT_SIDE_SPLITTER_DIST = "main-right-side-splitter-dist";
+ public const string MAIN_REFERENCES_HEIGHT = "main-references-height";
+ public const string MAIN_SYMBOLS_HEIGHT = "main-symbols-height";
// New project dialog.
public const string NEWP_SELECTED_SYSTEM = "newp-selected-system";
diff --git a/SourceGenWPF/MainController.cs b/SourceGenWPF/MainController.cs
index 9279367..1eda803 100644
--- a/SourceGenWPF/MainController.cs
+++ b/SourceGenWPF/MainController.cs
@@ -24,7 +24,9 @@ using System.Windows;
using Asm65;
using CommonUtil;
+using CommonWPF;
using SourceGenWPF.ProjWin;
+using SourceGenWPF.Sandbox;
namespace SourceGenWPF {
///
@@ -35,6 +37,8 @@ namespace SourceGenWPF {
/// There is some Windows-specific stuff, like MessageBox and OpenFileDialog.
///
public class MainController {
+ private const string SETTINGS_FILE_NAME = "SourceGen-settings";
+
#region Project state
// Currently open project, or null if none.
@@ -46,14 +50,6 @@ namespace SourceGenWPF {
// Pathname of .dis65 file. This will be empty for a new project.
private string mProjectPathName;
-#if false
- ///
- /// Symbol subset, used to supply data to the symbol ListView. Initialized with
- /// an empty symbol table.
- ///
- private SymbolTableSubset mSymbolSubset;
-#endif
-
///
/// Data backing the code list.
///
@@ -155,6 +151,18 @@ namespace SourceGenWPF {
mMainWin = win;
}
+ ///
+ /// Early initialization, before the window is visible. Notably, we want to get the
+ /// window placement data, so we can position and size the window before it's first
+ /// drawn (avoids a blink).
+ ///
+ public void WindowSourceInitialized() {
+ // Load the settings from the file. If this fails we have no way to tell the user,
+ // so just keep going.
+ LoadAppSettings();
+ SetAppWindowLocation();
+ }
+
///
/// Perform one-time initialization after the Window has finished loading. We defer
/// to this point so we can report fatal errors directly to the user.
@@ -167,7 +175,6 @@ namespace SourceGenWPF {
Application.Current.Shutdown();
return;
}
-#if false
try {
PluginDllCache.PreparePluginDir();
} catch (Exception ex) {
@@ -175,61 +182,20 @@ namespace SourceGenWPF {
if (pluginPath == null) {
pluginPath = "??>";
}
- string msg = string.Format(Properties.Resources.PLUGIN_DIR_FAIL,
+ string msg = string.Format(Res.Strings.PLUGIN_DIR_FAIL_FMT,
pluginPath + ": " + ex.Message);
- MessageBox.Show(this, msg, Properties.Resources.PLUGIN_DIR_FAIL_CAPTION,
- MessageBoxButtons.OK, MessageBoxIcon.Error);
- Application.Exit();
+ MessageBox.Show(msg, Res.Strings.PLUGIN_DIR_FAIL_CAPTION,
+ MessageBoxButton.OK, MessageBoxImage.Error);
+ Application.Current.Shutdown();
return;
}
-#endif
-
-#if false
- logoPictureBox.ImageLocation = RuntimeDataAccess.GetPathName(LOGO_FILE_NAME);
- versionLabel.Text = string.Format(Properties.Resources.VERSION_FMT,
- Program.ProgramVersion);
-
- toolStripStatusLabel.Text = Properties.Resources.STATUS_READY;
-
- mProjectControl = this.codeListView;
- mNoProjectControl = this.noProjectPanel;
-
- // Clone the menu structure from the designer. The same items are used for
- // both Edit > Actions and the right-click context menu in codeListView.
- mActionsMenuItems = new ToolStripItem[actionsToolStripMenuItem.DropDownItems.Count];
- for (int i = 0; i < actionsToolStripMenuItem.DropDownItems.Count; i++) {
- mActionsMenuItems[i] = actionsToolStripMenuItem.DropDownItems[i];
- }
-#endif
-
-#if false
- // Load the settings from the file. Some things (like the symbol subset) need
- // these. The general "apply settings" doesn't happen until a bit later, after
- // the sub-windows have been initialized.
- LoadAppSettings();
-
- // Init primary ListView (virtual, ownerdraw)
- InitCodeListView();
-
- // Init Symbols ListView (virtual, non-ownerdraw)
- mSymbolSubset = new SymbolTableSubset(new SymbolTable());
- symbolListView.SetDoubleBuffered(true);
- InitSymbolListView();
-
- // Init References ListView (non-virtual, non-ownerdraw)
- referencesListView.SetDoubleBuffered(true);
// Place the main window and apply the various settings.
- SetAppWindowLocation();
-#endif
ApplyAppSettings();
#if false
- UpdateActionMenu();
UpdateMenuItemsAndTitle();
UpdateRecentLinks();
-
- ShowNoProject();
#endif
ProcessCommandLine();
@@ -242,6 +208,163 @@ namespace SourceGenWPF {
}
}
+
+ ///
+ /// Loads settings from the settings file into AppSettings.Global. Does not apply
+ /// them to the ProjectView.
+ ///
+ private void LoadAppSettings() {
+ AppSettings settings = AppSettings.Global;
+
+ // Set some default settings for first-time use. The general rule is to set
+ // a default value of false, 0, or the empty string, so we only need to set
+ // values here when that isn't the case. The point at which the setting is
+ // actually used is expected to do something reasonable by default.
+
+ settings.SetBool(AppSettings.SYMWIN_SHOW_USER, true);
+ settings.SetBool(AppSettings.SYMWIN_SHOW_PROJECT, true);
+ settings.SetBool(AppSettings.SYMWIN_SHOW_PLATFORM, false);
+ settings.SetBool(AppSettings.SYMWIN_SHOW_AUTO, false);
+ settings.SetBool(AppSettings.SYMWIN_SHOW_CONST, true);
+ settings.SetBool(AppSettings.SYMWIN_SHOW_ADDR, true);
+ settings.SetBool(AppSettings.SYMWIN_SORT_ASCENDING, true);
+ settings.SetInt(AppSettings.SYMWIN_SORT_COL, (int)Symbol.SymbolSortField.Name);
+
+ settings.SetBool(AppSettings.FMT_UPPER_OPERAND_A, true);
+ settings.SetBool(AppSettings.FMT_UPPER_OPERAND_S, true);
+ settings.SetBool(AppSettings.FMT_ADD_SPACE_FULL_COMMENT, true);
+ settings.SetString(AppSettings.FMT_OPCODE_SUFFIX_LONG, "l");
+ settings.SetString(AppSettings.FMT_OPERAND_PREFIX_ABS, "a:");
+ settings.SetString(AppSettings.FMT_OPERAND_PREFIX_LONG, "f:");
+
+ settings.SetBool(AppSettings.SRCGEN_ADD_IDENT_COMMENT, true);
+ settings.SetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, true);
+
+#if DEBUG
+ settings.SetBool(AppSettings.DEBUG_MENU_ENABLED, true);
+#else
+ settings.SetBool(AppSettings.DEBUG_MENU_ENABLED, false);
+#endif
+
+ // Load the settings file, and merge it into the globals.
+ string runtimeDataDir = RuntimeDataAccess.GetDirectory();
+ if (runtimeDataDir == null) {
+ Debug.WriteLine("Unable to load settings file");
+ return;
+ }
+ string settingsDir = Path.GetDirectoryName(runtimeDataDir);
+ string settingsPath = Path.Combine(settingsDir, SETTINGS_FILE_NAME);
+ try {
+ string text = File.ReadAllText(settingsPath);
+ AppSettings fileSettings = AppSettings.Deserialize(text);
+ AppSettings.Global.MergeSettings(fileSettings);
+ Debug.WriteLine("Settings file loaded and merged");
+ } catch (Exception ex) {
+ Debug.WriteLine("Unable to read settings file: " + ex.Message);
+ }
+ }
+
+ ///
+ /// Saves AppSettings to a file.
+ ///
+ private void SaveAppSettings() {
+ if (!AppSettings.Global.Dirty) {
+ Debug.WriteLine("Settings not dirty, not saving");
+ return;
+ }
+
+ // Main window position and size.
+ AppSettings.Global.SetString(AppSettings.MAIN_WINDOW_PLACEMENT,
+ mMainWin.GetPlacement());
+
+ // Horizontal splitters.
+ AppSettings.Global.SetInt(AppSettings.MAIN_LEFT_PANEL_WIDTH,
+ (int)mMainWin.LeftPanelWidth);
+ AppSettings.Global.SetInt(AppSettings.MAIN_RIGHT_PANEL_WIDTH,
+ (int)mMainWin.RightPanelWidth);
+
+ // Vertical splitters.
+ AppSettings.Global.SetInt(AppSettings.MAIN_REFERENCES_HEIGHT,
+ (int)mMainWin.ReferencesPanelHeight);
+ AppSettings.Global.SetInt(AppSettings.MAIN_SYMBOLS_HEIGHT,
+ (int)mMainWin.SymbolsPanelHeight);
+
+#if false
+ SerializeCodeListColumnWidths();
+ SerializeReferencesColumnWidths();
+ SerializeNotesColumnWidths();
+ SerializeSymbolColumnWidths();
+#endif
+
+ string runtimeDataDir = RuntimeDataAccess.GetDirectory();
+ if (runtimeDataDir == null) {
+ Debug.WriteLine("Unable to save settings file");
+ return;
+ }
+ string settingsDir = Path.GetDirectoryName(runtimeDataDir);
+ string settingsPath = Path.Combine(settingsDir, SETTINGS_FILE_NAME);
+ try {
+ string cereal = AppSettings.Global.Serialize();
+ File.WriteAllText(settingsPath, cereal);
+ AppSettings.Global.Dirty = false;
+ Debug.WriteLine("Saved settings (" + settingsPath + ")");
+ } catch (Exception ex) {
+ Debug.WriteLine("Failed to save settings: " + ex.Message);
+ }
+ }
+
+ ///
+ /// Replaces the contents of the global settings object with the new settings,
+ /// then applies them to the project.
+ ///
+ ///
+ public void SetAppSettings(AppSettings settings) {
+ AppSettings.Global.ReplaceSettings(settings);
+ ApplyAppSettings();
+
+ // We get called whenever Apply or OK is hit in the settings editor, so it's
+ // a pretty good time to save the settings out.
+ SaveAppSettings();
+ }
+
+ ///
+ /// Sets the app window's location and size. This should be called before the window has
+ /// finished initialization.
+ ///
+ private void SetAppWindowLocation() {
+ const int DEFAULT_SPLIT = 250;
+
+ AppSettings settings = AppSettings.Global;
+
+ string placement = settings.GetString(AppSettings.MAIN_WINDOW_PLACEMENT, null);
+ if (placement != null) {
+ mMainWin.SetPlacement(placement);
+ }
+
+ mMainWin.LeftPanelWidth =
+ settings.GetInt(AppSettings.MAIN_LEFT_PANEL_WIDTH, DEFAULT_SPLIT);
+ mMainWin.RightPanelWidth =
+ settings.GetInt(AppSettings.MAIN_RIGHT_PANEL_WIDTH, DEFAULT_SPLIT);
+ mMainWin.ReferencesPanelHeight =
+ settings.GetInt(AppSettings.MAIN_REFERENCES_HEIGHT, 350);
+ mMainWin.SymbolsPanelHeight =
+ settings.GetInt(AppSettings.MAIN_SYMBOLS_HEIGHT, 400);
+
+#if false
+ // Configure column widths.
+ string widthStr = settings.GetString(AppSettings.CDLV_COL_WIDTHS, null);
+ if (!string.IsNullOrEmpty(widthStr)) {
+ CodeListColumnWidths widths = CodeListColumnWidths.Deserialize(widthStr);
+ if (widths != null) {
+ SetCodeListHeaderWidths(widths);
+ }
+ }
+ DeserializeReferencesColumnWidths();
+ DeserializeNotesColumnWidths();
+ DeserializeSymbolColumnWidths();
+#endif
+ }
+
///
/// Applies "actionable" settings to the ProjectView, pulling them out of the global
/// settings object. If a project is open, refreshes the display list and all sub-windows.
@@ -363,8 +486,6 @@ namespace SourceGenWPF {
#endregion Init and settings
-
-
#region Project management
private bool PrepareNewProject(string dataPathName, SystemDef sysDef) {
@@ -891,14 +1012,21 @@ namespace SourceGenWPF {
// Update this, in case this was a new project.
UpdateRecentProjectList(pathName);
-#if false
// Seems like a good time to save this off too.
SaveAppSettings();
-#endif
return true;
}
+ ///
+ /// Handles main window closing.
+ ///
+ /// True if it's okay for the window to close, false to cancel it.
+ public bool WindowClosing() {
+ SaveAppSettings();
+ return CloseProject();
+ }
+
///
/// Closes the project and associated modeless dialogs. Unsaved changes will be
/// lost, so if the project has outstanding changes the user will be given the
diff --git a/SourceGenWPF/ProjWin/MainWindow.xaml b/SourceGenWPF/ProjWin/MainWindow.xaml
index 389b8fd..dee8772 100644
--- a/SourceGenWPF/ProjWin/MainWindow.xaml
+++ b/SourceGenWPF/ProjWin/MainWindow.xaml
@@ -24,8 +24,12 @@ limitations under the License.
Title="6502bench SourceGen"
Icon="/SourceGenWPF;component/Res/SourceGenIcon.ico"
Width="1000" Height="600" MinWidth="800" MinHeight="500"
+ SourceInitialized="Window_SourceInitialized"
Loaded="Window_Loaded"
- MouseDown="Window_MouseDown">
+ LocationChanged="Window_LocationChanged"
+ SizeChanged="Window_SizeChanged"
+ MouseDown="Window_MouseDown"
+ Closing="Window_Closing">
@@ -245,12 +249,12 @@ limitations under the License.
-
-
+
+
-
+
@@ -374,9 +378,9 @@ limitations under the License.
-
+
-
+
@@ -430,7 +434,7 @@ limitations under the License.
+ HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
diff --git a/SourceGenWPF/ProjWin/MainWindow.xaml.cs b/SourceGenWPF/ProjWin/MainWindow.xaml.cs
index 64acab2..044a03b 100644
--- a/SourceGenWPF/ProjWin/MainWindow.xaml.cs
+++ b/SourceGenWPF/ProjWin/MainWindow.xaml.cs
@@ -77,6 +77,20 @@ namespace SourceGenWPF.ProjWin {
AddMultiKeyGestures();
+ // Get an event when the splitters move. Because of the way things are set up, it's
+ // actually best to get an event when the grid row/column sizes change.
+ // https://stackoverflow.com/a/22495586/294248
+ DependencyPropertyDescriptor widthDesc = DependencyPropertyDescriptor.FromProperty(
+ ColumnDefinition.WidthProperty, typeof(ItemsControl));
+ DependencyPropertyDescriptor heightDesc = DependencyPropertyDescriptor.FromProperty(
+ RowDefinition.HeightProperty, typeof(ItemsControl));
+ // main window, left/right panels
+ widthDesc.AddValueChanged(triptychGrid.ColumnDefinitions[0], GridSizeChanged);
+ widthDesc.AddValueChanged(triptychGrid.ColumnDefinitions[4], GridSizeChanged);
+ // references vs. notes
+ heightDesc.AddValueChanged(leftPanel.RowDefinitions[0], GridSizeChanged);
+ heightDesc.AddValueChanged(rightPanel.RowDefinitions[0], GridSizeChanged);
+
//GridView gv = (GridView)codeListView.View;
//gv.Columns[0].Width = 50;
}
@@ -110,18 +124,6 @@ namespace SourceGenWPF.ProjWin {
}));
}
- private void Window_Loaded(object sender, RoutedEventArgs e) {
- mMainCtrl.WindowLoaded();
- CreateCodeListContextMenu();
-
-#if DEBUG
- // Get more info on CollectionChanged events that do not agree with current
- // state of Items collection.
- PresentationTraceSources.SetTraceLevel(codeListView.ItemContainerGenerator,
- PresentationTraceLevel.High);
-#endif
- }
-
private void CreateCodeListContextMenu() {
// Find Actions menu.
ItemCollection mainItems = this.appMenu.Items;
@@ -206,6 +208,46 @@ namespace SourceGenWPF.ProjWin {
get { return mShowCodeListView ? Visibility.Visible : Visibility.Hidden; }
}
+
+ ///
+ /// Handles source-initialized event. This happens before Loaded, before the window
+ /// is visible, which makes it a good time to set the size and position.
+ ///
+ private void Window_SourceInitialized(object sender, EventArgs e) {
+ mMainCtrl.WindowSourceInitialized();
+ }
+
+ ///
+ /// Handles window-loaded event. Window is ready to go, so we can start doing things
+ /// that involve user interaction.
+ ///
+ private void Window_Loaded(object sender, RoutedEventArgs e) {
+ mMainCtrl.WindowLoaded();
+ CreateCodeListContextMenu();
+
+#if DEBUG
+ // Get more info on CollectionChanged events that do not agree with current
+ // state of Items collection.
+ PresentationTraceSources.SetTraceLevel(codeListView.ItemContainerGenerator,
+ PresentationTraceLevel.High);
+#endif
+ }
+
+ ///
+ /// Handles window-close event. The user has an opportunity to cancel.
+ ///
+ private void Window_Closing(object sender, CancelEventArgs e) {
+ Debug.WriteLine("Main app window closing");
+ if (mMainCtrl == null) {
+ // early failure?
+ return;
+ }
+ if (!mMainCtrl.WindowClosing()) {
+ e.Cancel = true;
+ return;
+ }
+ }
+
///
/// Catch mouse-down events so we can treat the fourth mouse button as "back".
///
@@ -215,6 +257,61 @@ namespace SourceGenWPF.ProjWin {
}
}
+ #region Window placement
+
+ //
+ // We record the location and size of the window, and the sizes of the panels, in
+ // the settings file. All we need to do here is note that something has changed.
+ //
+ private void Window_LocationChanged(object sender, EventArgs e) {
+ Debug.WriteLine("Main window location changed");
+ AppSettings.Global.Dirty = true;
+ }
+ private void Window_SizeChanged(object sender, SizeChangedEventArgs e) {
+ Debug.WriteLine("Main window size changed");
+ AppSettings.Global.Dirty = true;
+ }
+ private void GridSizeChanged(object sender, EventArgs e) {
+ Debug.WriteLine("Splitter size change");
+ AppSettings.Global.Dirty = true;
+ }
+
+ public double LeftPanelWidth {
+ get { return triptychGrid.ColumnDefinitions[0].ActualWidth; }
+ set { triptychGrid.ColumnDefinitions[0].Width = new GridLength(value); }
+ }
+ public double RightPanelWidth {
+ get { return triptychGrid.ColumnDefinitions[4].ActualWidth; }
+ set { triptychGrid.ColumnDefinitions[4].Width = new GridLength(value); }
+ }
+ public double ReferencesPanelHeight {
+ get { return leftPanel.RowDefinitions[0].ActualHeight; }
+ set {
+ // If you set the height to a pixel value, you lose the auto-sizing behavior,
+ // and the splitter will happily shove the bottom panel off the bottom of the
+ // main window. The trick is to use "star" units.
+ // Thanks: https://stackoverflow.com/q/35000893/294248
+ double totalHeight = leftPanel.RowDefinitions[0].ActualHeight +
+ leftPanel.RowDefinitions[2].ActualHeight;
+ leftPanel.RowDefinitions[0].Height = new GridLength(value, GridUnitType.Star);
+ leftPanel.RowDefinitions[2].Height = new GridLength(totalHeight - value,
+ GridUnitType.Star);
+ }
+ }
+ public double SymbolsPanelHeight {
+ get { return rightPanel.RowDefinitions[0].ActualHeight; }
+ set {
+ double totalHeight = rightPanel.RowDefinitions[0].ActualHeight +
+ rightPanel.RowDefinitions[2].ActualHeight;
+ rightPanel.RowDefinitions[0].Height = new GridLength(value, GridUnitType.Star);
+ rightPanel.RowDefinitions[2].Height = new GridLength(totalHeight - value,
+ GridUnitType.Star);
+ }
+ }
+
+ #endregion Window placement
+
+
///
/// Sets the focus on the code list.
///
diff --git a/SourceGenWPF/Res/Strings.xaml b/SourceGenWPF/Res/Strings.xaml
index 7ea4d38..d60c87e 100644
--- a/SourceGenWPF/Res/Strings.xaml
+++ b/SourceGenWPF/Res/Strings.xaml
@@ -61,6 +61,8 @@ 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
+ Failed while preparing the plugin directory {0}
+ Failed Preparing Plugin Directory
Executing assembler...
Generating {0}...
comment
diff --git a/SourceGenWPF/Res/Strings.xaml.cs b/SourceGenWPF/Res/Strings.xaml.cs
index 3379a1d..b607809 100644
--- a/SourceGenWPF/Res/Strings.xaml.cs
+++ b/SourceGenWPF/Res/Strings.xaml.cs
@@ -102,6 +102,10 @@ namespace SourceGenWPF.Res {
(string)Application.Current.FindResource("str_OpenDataWrongLengthFmt");
public static string OPERATION_FAILED =
(string)Application.Current.FindResource("str_OperationFailed");
+ public static string PLUGIN_DIR_FAIL_FMT =
+ (string)Application.Current.FindResource("str_PluginDirFailFmt");
+ public static string PLUGIN_DIR_FAIL_CAPTION =
+ (string)Application.Current.FindResource("str_PluginDirFailCaption");
public static string PROGRESS_ASSEMBLING =
(string)Application.Current.FindResource("str_ProgressAssembling");
public static string PROGRESS_GENERATING_FMT =