1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-06-25 05:29:31 +00:00

Implement Find / Find Next

Also, tweaked Edit Label a bit.  I figured out how to make the
TextBox SelectAll+Focus work when the text is bound to a property.
This commit is contained in:
Andy McFadden 2019-07-07 13:28:45 -07:00
parent 741f7ef46a
commit 779566c236
10 changed files with 244 additions and 27 deletions

View File

@ -1442,6 +1442,70 @@ namespace SourceGenWPF {
}
}
public void Find() {
FindBox dlg = new FindBox(mMainWin, mFindString);
if (dlg.ShowDialog() == true) {
mFindString = dlg.TextToFind;
mFindStartIndex = -1;
FindText();
}
}
public void FindNext() {
FindText();
}
private void FindText() {
if (string.IsNullOrEmpty(mFindString)) {
return;
}
// Start from the topmost selected line, or the start of the file if nothing
// is selected.
int index = mMainWin.CodeListView_GetFirstSelectedIndex();
if (index < 0) {
index = 0;
}
// Start one past the selected item.
index++;
if (index == CodeLineList.Count) {
index = 0;
}
//Debug.WriteLine("FindText index=" + index + " start=" + mFindStartIndex +
// " str=" + mFindString);
while (index != mFindStartIndex) {
if (mFindStartIndex < 0) {
// need to latch this inside the loop so the initial test doesn't fail
mFindStartIndex = index;
}
string searchStr = CodeLineList.GetSearchString(index);
int matchPos = searchStr.IndexOf(mFindString,
StringComparison.InvariantCultureIgnoreCase);
if (matchPos >= 0) {
//Debug.WriteLine("Match " + index + ": " + searchStr);
mMainWin.CodeListView_EnsureVisible(index);
mMainWin.CodeListView_DeselectAll();
mMainWin.CodeListView_SelectRange(index, 1);
return;
}
index++;
if (index == CodeLineList.Count) {
index = 0;
}
}
// Announce that we've wrapped around, then clear the start index.
MessageBox.Show(Res.Strings.FIND_REACHED_START,
Res.Strings.FIND_REACHED_START_CAPTION, MessageBoxButton.OK,
MessageBoxImage.Information);
mFindStartIndex = -1;
mMainWin.CodeListView_Focus();
}
/// <summary>
/// Moves the view and selection to the specified offset. We want to select stuff
/// differently if we're jumping to a note vs. jumping to an instruction.

View File

@ -60,6 +60,8 @@ limitations under the License.
<system:String x:Key="str_FileFilterDis65">SourceGen projects(*.dis65)|*.dis65</system:String>
<system:String x:Key="str_FileFilterSym65">SourceGen symbols (*.sym65)|*.sym65</system:String>
<system:String x:Key="str_FileInfoFmt">File is {0:N1} KB of raw data.</system:String>
<system:String x:Key="str_FindReachedStart">Find reached the starting point of the search.</system:String>
<system:String x:Key="str_FindReachedStartCaption">Find...</system:String>
<system:String x:Key="str_FontDescriptorFmt">{0}-point {1}</system:String>
<system:String x:Key="str_GeneratedForVersion">Target assembler: {0} v{1} [{2}]</system:String>
<system:String x:Key="str_HideCol">Hide</system:String>

View File

@ -105,6 +105,10 @@ namespace SourceGenWPF.Res {
(string)Application.Current.FindResource("str_FileFilterSym65");
public static string FILE_INFO_FMT =
(string)Application.Current.FindResource("str_FileInfoFmt");
public static string FIND_REACHED_START =
(string)Application.Current.FindResource("str_FindReachedStart");
public static string FIND_REACHED_START_CAPTION =
(string)Application.Current.FindResource("str_FindReachedStartCaption");
public static string FONT_DESCRIPTOR_FMT =
(string)Application.Current.FindResource("str_FontDescriptorFmt");
public static string GENERATED_FOR_VERSION_FMT =

View File

@ -93,6 +93,9 @@
<Compile Include="WpfGui\EditProjectProperties.xaml.cs">
<DependentUpon>EditProjectProperties.xaml</DependentUpon>
</Compile>
<Compile Include="WpfGui\FindBox.xaml.cs">
<DependentUpon>FindBox.xaml</DependentUpon>
</Compile>
<Compile Include="WpfGui\FontPicker.xaml.cs">
<DependentUpon>FontPicker.xaml</DependentUpon>
</Compile>
@ -211,6 +214,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="WpfGui\FindBox.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="WpfGui\FontPicker.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>

View File

@ -24,7 +24,8 @@ limitations under the License.
Title="Edit Label"
SizeToContent="WidthAndHeight" ResizeMode="NoResize"
ShowInTaskbar="False" WindowStartupLocation="CenterOwner"
Loaded="Window_Loaded">
Loaded="Window_Loaded"
ContentRendered="Window_ContentRendered">
<Grid Margin="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
@ -38,15 +39,15 @@ limitations under the License.
<StackPanel Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2">
<TextBlock Text="Enter label:"/>
<TextBox Name="labelTextBox" Margin="0,2,0,0" FontFamily="{StaticResource GeneralMonoFont}"
FontSize="16" TextChanged="LabelTextBox_TextChanged"/>
Text="{Binding LabelText}" TextChanged="LabelTextBox_TextChanged"/>
<TextBlock Name="maxLengthLabel" Text="• Must be 2-32 characters long (or blank to remove)"
Margin="0,3,0,0"/>
Margin="0,7,0,0"/>
<TextBlock Name="firstLetterLabel" Text="• Must start with a letter or underscore"/>
<TextBlock Name="validCharsLabel" Text="• Valid characters are ASCII letters, numbers, and underscore"/>
<TextBlock Name="notDuplicateLabel" Text="• Must not be a duplicate of an existing label"/>
</StackPanel>
<GroupBox Grid.Column="0" Grid.Row="1" Header="Label Type" Margin="0,8,0,0">
<GroupBox Grid.Column="0" Grid.Row="1" Header="Label Type" Margin="0,12,0,0">
<StackPanel>
<RadioButton Name="radioButtonLocal" Content="_Local (if possible)" Margin="0,4,0,0"/>
<RadioButton Name="radioButtonGlobal" Content="_Global" Margin="0,4,0,0"/>

View File

@ -56,20 +56,17 @@ namespace SourceGenWPF.WpfGui {
}
private bool mIsValid;
// Doing it this way prevents the SelectAll+Focus on the field from working,
// presumably because the text change notification kills the selection. There may
// be a way around it, but I'm just going to use the WinForms approach for now.
///// <summary>
///// Property backing the text in the text entry box.
///// </summary>
//public string LabelText {
// get { return mLabelText; }
// set {
// mLabelText = value;
// OnPropertyChanged();
// }
//}
//string mLabelText;
/// <summary>
/// Property backing the text in the text entry box.
/// </summary>
public string LabelText {
get { return mLabelText; }
set {
mLabelText = value;
OnPropertyChanged();
}
}
string mLabelText;
// INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
@ -92,10 +89,10 @@ namespace SourceGenWPF.WpfGui {
mDefaultLabelColor = maxLengthLabel.Foreground;
if (LabelSym == null) {
labelTextBox.Text = string.Empty;
LabelText = string.Empty;
radioButtonLocal.IsChecked = true;
} else {
labelTextBox.Text = LabelSym.Label;
LabelText = LabelSym.Label;
switch (LabelSym.SymbolType) {
case Symbol.Type.LocalOrGlobalAddr:
radioButtonLocal.IsChecked = true;
@ -112,13 +109,15 @@ namespace SourceGenWPF.WpfGui {
break;
}
}
}
private void Window_ContentRendered(object sender, EventArgs e) {
labelTextBox.SelectAll();
labelTextBox.Focus();
}
private void LabelTextBox_TextChanged(object sender, RoutedEventArgs e) {
string str = labelTextBox.Text;
string str = LabelText;
bool valid = true;
if (str.Length == 1 || str.Length > Asm65.Label.MAX_LABEL_LEN) {
@ -174,7 +173,7 @@ namespace SourceGenWPF.WpfGui {
}
private void OkButton_Click(object sender, RoutedEventArgs e) {
if (string.IsNullOrEmpty(labelTextBox.Text)) {
if (string.IsNullOrEmpty(LabelText)) {
LabelSym = null;
} else {
Symbol.Type symbolType;
@ -188,7 +187,7 @@ namespace SourceGenWPF.WpfGui {
Debug.Assert(false); // WTF
symbolType = Symbol.Type.LocalOrGlobalAddr;
}
LabelSym = new Symbol(labelTextBox.Text, mAddress, Symbol.Source.User, symbolType);
LabelSym = new Symbol(LabelText, mAddress, Symbol.Source.User, symbolType);
}
DialogResult = true;
}

View File

@ -0,0 +1,34 @@
<!--
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.
-->
<Window x:Class="SourceGenWPF.WpfGui.FindBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SourceGenWPF.WpfGui"
mc:Ignorable="d"
Title="Find..."
SizeToContent="WidthAndHeight" ResizeMode="NoResize"
ShowInTaskbar="False" WindowStartupLocation="CenterOwner"
ContentRendered="Window_ContentRendered"
PreviewKeyDown="Window_KeyEventHandler">
<StackPanel Margin="8" Orientation="Horizontal">
<TextBox Name="findTextBox" Width="200" Text="{Binding TextToFind}"/>
<Button Content="Find" Width="70" IsDefault="True" Margin="16,0,0,0"
Click="OkButton_Click"/>
</StackPanel>
</Window>

View File

@ -0,0 +1,83 @@
/*
* 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.Runtime.CompilerServices;
using System.Text;
using System.Windows;
using System.Windows.Input;
namespace SourceGenWPF.WpfGui {
/// <summary>
/// Find text dialog.
/// </summary>
public partial class FindBox : Window, INotifyPropertyChanged {
/// <summary>
/// Text to find. On success, holds the string searched for. This is bound to the
/// text field.
/// </summary>
public string TextToFind {
get { return mTextToFind; }
set {
mTextToFind = value;
OnPropertyChanged();
}
}
private string mTextToFind;
// INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = "") {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
/// <summary>
/// Constructor. Pass in the last string searched for, to use as the initial value.
/// </summary>
public FindBox(Window owner, string findStr) {
InitializeComponent();
Owner = owner;
DataContext = this;
Debug.Assert(findStr != null);
TextToFind = findStr;
}
private void Window_ContentRendered(object sender, EventArgs e) {
findTextBox.Focus();
findTextBox.SelectAll();
}
/// <summary>
/// Handles key events, looking for the escape key.
/// </summary>
/// <remarks>
/// Required because we don't have a "cancel" button. Thanks:
/// https://stackoverflow.com/a/419615/294248
/// </remarks>
private void Window_KeyEventHandler(object sender, KeyEventArgs e) {
if (e.Key == Key.Escape) {
DialogResult = false;
}
}
private void OkButton_Click(object sender, RoutedEventArgs e) {
DialogResult = true;
}
}
}

View File

@ -64,6 +64,11 @@ limitations under the License.
</RoutedUICommand>
<RoutedUICommand x:Key="EditStatusFlagsCmd" Text="Override Status Flags..."/>
<RoutedUICommand x:Key="ExitCmd" Text="Exit"/>
<RoutedUICommand x:Key="FindNextCmd" Text="Find Next">
<RoutedUICommand.InputGestures>
<KeyGesture>F3</KeyGesture>
</RoutedUICommand.InputGestures>
</RoutedUICommand>
<RoutedUICommand x:Key="HintAsCodeEntryPointCmd" Text="Hint As Code Entry Point"/>
<RoutedUICommand x:Key="HintAsDataStartCmd" Text="Hint As Data Start"/>
<RoutedUICommand x:Key="HintAsInlineDataCmd" Text="Hint As Inline Data"/>
@ -124,6 +129,10 @@ limitations under the License.
CanExecute="CanEditStatusFlags" Executed="EditStatusFlagsCmd_Executed"/>
<CommandBinding Command="{StaticResource ExitCmd}"
Executed="ExitCmd_Executed"/>
<CommandBinding Command="Find"
CanExecute="IsProjectOpen" Executed="FindCmd_Executed"/>
<CommandBinding Command="{StaticResource FindNextCmd}"
CanExecute="IsProjectOpen" Executed="FindNextCmd_Executed"/>
<CommandBinding Command="Help"
Executed="HelpCmd_Executed"/>
<CommandBinding Command="{StaticResource HintAsCodeEntryPointCmd}"

View File

@ -617,7 +617,7 @@ namespace SourceGenWPF.WpfGui {
}
/// <summary>
/// Sets the code list selection.
/// Sets the code list selection to match the selection bitmap.
/// </summary>
/// <param name="sel">Selection bitmap.</param>
public void CodeListView_SetSelection(DisplayListSelection sel) {
@ -628,11 +628,10 @@ namespace SourceGenWPF.WpfGui {
codeListView.SelectAll();
return;
}
Debug.Assert(codeListView.SelectedItems.Count == 0); // expected
codeListView.SelectedItems.Clear(); // just in case
codeListView.SelectedItems.Clear();
if (sel.Count > MAX_SEL_COUNT) {
// Too much for WPF -- only restore the first item.
// Too much for WPF ListView -- only restore the first item.
Debug.WriteLine("SetSelection: not restoring (" + sel.Count + " items)");
codeListView.SelectedItems.Add(CodeDisplayList[sel.GetFirstSelectedIndex()]);
return;
@ -719,6 +718,13 @@ namespace SourceGenWPF.WpfGui {
}
}
/// <summary>
/// Ensures the the code ListView control has input focus.
/// </summary>
public void CodeListView_Focus() {
codeListView.Focus();
}
#endregion Selection management
@ -850,6 +856,14 @@ namespace SourceGenWPF.WpfGui {
Close();
}
private void FindCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
mMainCtrl.Find();
}
private void FindNextCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
mMainCtrl.FindNext();
}
private void HelpCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
mMainCtrl.ShowHelp();
}