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 =