1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-11-26 06:49:19 +00:00

Implement "recents" feature

Add the list of recent projects to File > Recent Projects when the
sub-menu opens.  Make the buttons on the launch panel work correctly.
This commit is contained in:
Andy McFadden 2019-06-22 14:41:09 -07:00
parent 7d2fe51b41
commit 6b29ce98f9
5 changed files with 151 additions and 76 deletions

View File

@ -66,7 +66,7 @@ namespace SourceGenWPF {
/// <summary>
/// List of recently-opened projects.
/// </summary>
private List<string> mRecentProjectPaths = new List<string>(MAX_RECENT_PROJECTS);
public List<string> RecentProjectPaths = new List<string>(MAX_RECENT_PROJECTS);
public const int MAX_RECENT_PROJECTS = 6;
/// <summary>
@ -195,8 +195,8 @@ namespace SourceGenWPF {
#if false
UpdateMenuItemsAndTitle();
UpdateRecentLinks();
#endif
mMainWin.UpdateRecentLinks();
ProcessCommandLine();
}
@ -405,10 +405,12 @@ namespace SourceGenWPF {
Debug.WriteLine("Font convert failed: " + ex.Message);
}
}
#endif
// Unpack the recent-project list.
UnpackRecentProjectList();
#if false
// Enable the DEBUG menu if configured.
bool showDebugMenu = AppSettings.Global.GetBool(AppSettings.DEBUG_MENU_ENABLED, false);
if (dEBUGToolStripMenuItem.Visible != showDebugMenu) {
@ -427,6 +429,24 @@ namespace SourceGenWPF {
}
}
private void UnpackRecentProjectList() {
RecentProjectPaths.Clear();
string cereal = AppSettings.Global.GetString(
AppSettings.PRVW_RECENT_PROJECT_LIST, null);
if (string.IsNullOrEmpty(cereal)) {
return;
}
try {
JavaScriptSerializer ser = new JavaScriptSerializer();
RecentProjectPaths = ser.Deserialize<List<string>>(cereal);
} catch (Exception ex) {
Debug.WriteLine("Failed deserializing recent projects: " + ex.Message);
return;
}
}
/// <summary>
/// Ensures that the named project is at the top of the list. If it's elsewhere
/// in the list, move it to the top. Excess items are removed.
@ -438,32 +458,30 @@ namespace SourceGenWPF {
// without having saved it.
return;
}
int index = mRecentProjectPaths.IndexOf(projectPath);
int index = RecentProjectPaths.IndexOf(projectPath);
if (index == 0) {
// Already in the list, nothing changes. No need to update anything else.
return;
}
if (index > 0) {
mRecentProjectPaths.RemoveAt(index);
RecentProjectPaths.RemoveAt(index);
}
mRecentProjectPaths.Insert(0, projectPath);
RecentProjectPaths.Insert(0, projectPath);
// Trim the list to the max allowed.
while (mRecentProjectPaths.Count > MAX_RECENT_PROJECTS) {
while (RecentProjectPaths.Count > MAX_RECENT_PROJECTS) {
Debug.WriteLine("Recent projects: dropping " +
mRecentProjectPaths[MAX_RECENT_PROJECTS]);
mRecentProjectPaths.RemoveAt(MAX_RECENT_PROJECTS);
RecentProjectPaths[MAX_RECENT_PROJECTS]);
RecentProjectPaths.RemoveAt(MAX_RECENT_PROJECTS);
}
// Store updated list in app settings. JSON-in-JSON is ugly and inefficient,
// but it'll do for now.
JavaScriptSerializer ser = new JavaScriptSerializer();
string cereal = ser.Serialize(mRecentProjectPaths);
string cereal = ser.Serialize(RecentProjectPaths);
AppSettings.Global.SetString(AppSettings.PRVW_RECENT_PROJECT_LIST, cereal);
#if false
UpdateRecentLinks();
#endif
mMainWin.UpdateRecentLinks();
}
#endregion Init and settings
@ -761,12 +779,7 @@ namespace SourceGenWPF {
if (!CloseProject()) {
return;
}
//DoOpenFile(mRecentProjectPaths[projIndex]);
if (projIndex == 0) {
DoOpenFile(@"C:\Src\6502bench\EXTRA\ZIPPY#ff2000.dis65");
} else {
DoOpenFile(@"C:\Src\6502bench\EXTRA\CRYLLAN.MISSION#b30100.dis65");
}
DoOpenFile(RecentProjectPaths[projIndex]);
}
/// <summary>
@ -1027,7 +1040,7 @@ namespace SourceGenWPF {
/// </summary>
/// <returns>True if the project was closed, false if the user chose to cancel.</returns>
public bool CloseProject() {
Debug.WriteLine("ProjectView.DoClose() - dirty=" +
Debug.WriteLine("CloseProject() - dirty=" +
(mProject == null ? "N/A" : mProject.IsDirty.ToString()));
if (mProject != null && mProject.IsDirty) {
DiscardChanges dlg = new DiscardChanges(mMainWin);
@ -1065,13 +1078,11 @@ namespace SourceGenWPF {
mDataPathName = null;
mProjectPathName = null;
mTargetHighlightIndex = -1;
#if false
mSymbolSubset = new SymbolTableSubset(new SymbolTable());
#endif
// Clear this to release the memory.
mMainWin.CodeDisplayList.Clear();
mMainWin.InfoPanelContents = String.Empty;
mMainWin.InfoPanelContents = string.Empty;
mMainWin.ShowCodeListView = false;
mGenerationLog = null;

View File

@ -73,6 +73,7 @@ limitations under the License.
<system:String x:Key="str_ProjectFieldTypeHint">type hint</system:String>
<system:String x:Key="str_ProjectFieldUserLabel">user-defined label</system:String>
<system:String x:Key="str_ProjectFromNewerApp">This project was created by a newer version of SourceGen. It may contain data that will be lost if the project is edited.</system:String>
<!--<system:String x:Key="str_RecentProjectLinkFmt">#{0}: {1}</system:String>-->
<system:String x:Key="str_RuntimeDirNotFound">The RuntimeData directory was not found. It should be in the same directory as the executable.</system:String>
<system:String x:Key="str_RuntimeDirNotFoundCaption">RuntimeData Not Found</system:String>
<system:String x:Key="str_SetupSystemSummaryFmt">{1} CPU @ {2} MHz</system:String>

View File

@ -126,6 +126,8 @@ namespace SourceGenWPF.Res {
(string)Application.Current.FindResource("str_ProjectFieldUserLabel");
public static string PROJECT_FROM_NEWER_APP =
(string)Application.Current.FindResource("str_ProjectFromNewerApp");
//public static string RECENT_PROJECT_LINK_FMT =
// (string)Application.Current.FindResource("str_RecentProjectLinkFmt");
public static string RUNTIME_DIR_NOT_FOUND =
(string)Application.Current.FindResource("str_RuntimeDirNotFound");
public static string RUNTIME_DIR_NOT_FOUND_CAPTION =

View File

@ -123,7 +123,7 @@ limitations under the License.
Executed="OpenCmd_Executed"/>
<CommandBinding Command="{StaticResource RemoveHintsCmd}"
CanExecute="CanRemoveHints" Executed="RemoveHintsCmd_Executed"/>
<CommandBinding Command="{StaticResource RecentProjectCmd}"
<CommandBinding Command="{StaticResource RecentProjectCmd}" x:Name="recentProjectCmd"
Executed="RecentProjectCmd_Executed"/>
<CommandBinding Command="{StaticResource RedoCmd}"
CanExecute="CanRedo" Executed="RedoCmd_Executed"/>
@ -150,7 +150,7 @@ limitations under the License.
<MenuItem Command="{StaticResource AssembleCmd}"/>
<MenuItem Command="Print"/>
<Separator/>
<MenuItem Header="Recent Projects">
<MenuItem Name="recentProjectsMenu" Header="Recent Projects" SubmenuOpened="RecentProjectsMenu_SubmenuOpened">
<MenuItem Header="(none)"/>
</MenuItem>
<Separator/>
@ -173,7 +173,7 @@ limitations under the License.
<Separator/>
<MenuItem Header="Settings..."/>
</MenuItem>
<MenuItem Name="ActionsMenu" Header="_Actions">
<MenuItem Name="actionsMenu" Header="_Actions">
<MenuItem Command="{StaticResource EditAddressCmd}"/>
<MenuItem Command="{StaticResource EditStatusFlagsCmd}"/>
<MenuItem Header="Edit Label..."/>
@ -351,14 +351,27 @@ limitations under the License.
</StackPanel>
<StackPanel Grid.Row="1" HorizontalAlignment="Left">
<Button Content="Start new project" Width="200" Height="50" Margin="10,30,10,10"/>
<Button Content="Open existing project" Width="200" Height="50" Margin="10"/>
<Button Content="Recent project #1" Width="200" Height="50" Margin="10"
CommandParameter="0"
Command="{DynamicResource RecentProjectCmd}"/>
<Button Content="Recent project #2" Width="200" Height="50" Margin="10"
CommandParameter="1"
Command="{DynamicResource RecentProjectCmd}"/>
<Button Content="Start new project" Width="240" Height="50" Margin="10,30,10,10"/>
<Button Content="Open existing project" Width="240" Height="50" Margin="10"
Command="{StaticResource OpenCmd}"/>
<Button Name="recentProjectButton1" Width="240" Height="50" Margin="10"
Command="{DynamicResource RecentProjectCmd}" CommandParameter="0">
<Button.Content>
<StackPanel>
<TextBlock HorizontalAlignment="Center">Recent project #1</TextBlock>
<TextBlock Name="recentProjectName1" HorizontalAlignment="Center">???</TextBlock>
</StackPanel>
</Button.Content>
</Button>
<Button Name="recentProjectButton2" Width="240" Height="50" Margin="10"
Command="{DynamicResource RecentProjectCmd}" CommandParameter="1">
<Button.Content>
<StackPanel>
<TextBlock HorizontalAlignment="Center">Recent project #2</TextBlock>
<TextBlock Name="recentProjectName2" HorizontalAlignment="Center">???</TextBlock>
</StackPanel>
</Button.Content>
</Button>
</StackPanel>
</Grid>

View File

@ -19,6 +19,7 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Windows;
@ -142,20 +143,19 @@ namespace SourceGenWPF.WpfGui {
}
private void CreateCodeListContextMenu() {
// Find Actions menu.
ItemCollection mainItems = this.appMenu.Items;
MenuItem actionsMenu = null;
foreach (object obj in mainItems) {
if (!(obj is MenuItem)) {
continue;
}
MenuItem mi = (MenuItem)obj;
if (mi.Name.Equals("ActionsMenu")) {
actionsMenu = mi;
break;
}
}
Debug.Assert(actionsMenu != null);
//// Find Actions menu.
//ItemCollection mainItems = this.appMenu.Items;
//foreach (object obj in mainItems) {
// if (!(obj is MenuItem)) {
// continue;
// }
// MenuItem mi = (MenuItem)obj;
// if (mi.Name.Equals("actionsMenu")) {
// actionsMenu = mi;
// break;
// }
//}
//Debug.Assert(actionsMenu != null);
// Clone the Actions menu into the codeListView context menu.
ContextMenu ctxt = this.codeListView.ContextMenu;
@ -335,6 +335,8 @@ namespace SourceGenWPF.WpfGui {
#endregion Window placement
#region Column widths
/// <summary>
/// Grabs the widths of the columns of the various grids and saves them in the
/// global AppSettings.
@ -416,32 +418,7 @@ namespace SourceGenWPF.WpfGui {
}
}
/// <summary>
/// Sets the focus on the code list.
/// </summary>
//public void CodeListView_Focus() {
// codeListView.Focus();
//}
/// <summary>
/// Handles a double-click on the code list. We have to figure out which row and
/// column were clicked, which is not easy in WPF.
/// </summary>
private void CodeListView_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
Debug.Assert(sender == codeListView);
ListViewItem lvi = codeListView.GetClickedItem(e);
if (lvi == null) {
return;
}
DisplayList.FormattedParts parts = (DisplayList.FormattedParts)lvi.Content;
int row = parts.ListIndex;
int col = codeListView.GetClickEventColumn(e);
if (col < 0) {
return;
}
mMainCtrl.HandleCodeListDoubleClick(row, col);
}
#endregion Column widths
#region Selection management
@ -658,6 +635,7 @@ namespace SourceGenWPF.WpfGui {
#endregion Selection management
#region Can-execute handlers
/// <summary>
@ -829,8 +807,15 @@ namespace SourceGenWPF.WpfGui {
}
private void RecentProjectCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
if (!int.TryParse((string)e.Parameter, out int recentIndex) ||
recentIndex < 0 || recentIndex >= MainController.MAX_RECENT_PROJECTS) {
int recentIndex;
if (e.Parameter is int) {
recentIndex = (int)e.Parameter;
} else if (e.Parameter is string) {
recentIndex = int.Parse((string)e.Parameter);
} else {
throw new Exception("Bad parameter: " + e.Parameter);
}
if (recentIndex < 0 || recentIndex >= MainController.MAX_RECENT_PROJECTS) {
throw new Exception("Bad parameter: " + e.Parameter);
}
@ -844,6 +829,69 @@ namespace SourceGenWPF.WpfGui {
#endregion Command handlers
#region Misc
/// <summary>
/// Handles a double-click on the code list. We have to figure out which row and
/// column were clicked, which is not easy in WPF.
/// </summary>
private void CodeListView_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
Debug.Assert(sender == codeListView);
ListViewItem lvi = codeListView.GetClickedItem(e);
if (lvi == null) {
return;
}
DisplayList.FormattedParts parts = (DisplayList.FormattedParts)lvi.Content;
int row = parts.ListIndex;
int col = codeListView.GetClickEventColumn(e);
if (col < 0) {
return;
}
mMainCtrl.HandleCodeListDoubleClick(row, col);
}
private void RecentProjectsMenu_SubmenuOpened(object sender, RoutedEventArgs e) {
MenuItem recents = (MenuItem)sender;
recents.Items.Clear();
Debug.WriteLine("COUNT is " + mMainCtrl.RecentProjectPaths.Count);
if (mMainCtrl.RecentProjectPaths.Count == 0) {
MenuItem mi = new MenuItem();
mi.Header = "(none)";
recents.Items.Add(mi);
} else {
for (int i = 0; i < mMainCtrl.RecentProjectPaths.Count; i++) {
MenuItem mi = new MenuItem();
mi.Header = string.Format("{0}: {1}", i + 1, mMainCtrl.RecentProjectPaths[i]);
mi.Command = recentProjectCmd.Command;
mi.CommandParameter = i;
recents.Items.Add(mi);
}
}
}
public void UpdateRecentLinks() {
List<string> pathList = mMainCtrl.RecentProjectPaths;
if (pathList.Count >= 1) {
recentProjectName1.Text = Path.GetFileName(pathList[0]);
recentProjectButton1.Visibility = Visibility.Visible;
} else {
recentProjectName1.Text = string.Empty;
recentProjectButton1.Visibility = Visibility.Collapsed;
}
if (pathList.Count >= 2) {
recentProjectName2.Text = Path.GetFileName(pathList[1]);
recentProjectButton2.Visibility = Visibility.Visible;
} else {
recentProjectName2.Text = string.Empty;
recentProjectButton2.Visibility = Visibility.Collapsed;
}
}
#endregion Misc
#region References panel