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

Implement Edit Label

The dialog is pretty straightforward.  This is the first editor that
can cause a partial update -- if you edit a label, only the lines
that refer to that label are regenerated -- so I added the code for
partial display list updates as well.

Also, while working on this I noticed that long comments were getting
ellipsized at a bad place.  The column width for the semi-hidden
column used for notes and long comments wasn't getting set.  After
fiddling with it a bit I determined that it really needed to be set to
the sum of the widths of the rightmost four columns, and updated
whenever column sizes change.  This was easier to do than I expected.
I may actually be getting the hang of WPF.
This commit is contained in:
Andy McFadden 2019-07-06 17:24:42 -07:00
parent 33c4b86b44
commit 741f7ef46a
10 changed files with 434 additions and 41 deletions

View File

@ -285,6 +285,33 @@ namespace SourceGenWPF {
SelectedIndices = new DisplayListSelection(size);
}
/// <summary>
/// A range of lines has been replaced with a new range of lines. The new set may be
/// the same size, larger, or smaller than the previous.
/// </summary>
/// <param name="startIndex">Start index of change area.</param>
/// <param name="oldCount">Number of old lines.</param>
/// <param name="newCount">Number of new lines. May be zero.</param>
public void ClearListSegment(int startIndex, int oldCount, int newCount) {
Debug.WriteLine("ClearListSegment start=" + startIndex + " old=" + oldCount +
" new=" + newCount);
Debug.Assert(startIndex >= 0 && startIndex < mList.Count);
Debug.Assert(oldCount > 0 && startIndex + oldCount < mList.Count);
Debug.Assert(newCount >= 0);
// Remove the old elements to clear them.
mList.RemoveRange(startIndex, oldCount);
// Replace with the appropriate number of null entries.
for (int i = 0; i < newCount; i++) {
mList.Insert(startIndex, null);
}
// TODO: can we null out existing entries, and just insert/remove when counts differ?
OnPropertyChanged(CountString);
OnPropertyChanged(IndexerName);
OnCollectionReset();
}
/// <summary>
/// List elements. Instances are immutable.
/// </summary>

View File

@ -609,7 +609,8 @@ namespace SourceGenWPF {
//Debug.WriteLine("DL gen range [" + startOffset + "," + endOffset + "]");
// Find the start index. The start offset should always appear at the
// start of a Line because it comes from item selection.
// start of a Line (as opposed to being in the middle of a multi-byte instruction)
// because it comes from item selection.
int startIndex = FindLineByOffset(mLineList, startOffset);
if (startIndex < 0) {
Debug.Assert(false, "Unable to find startOffset " + startOffset);
@ -654,7 +655,7 @@ namespace SourceGenWPF {
// Out with the old, in with the new.
mLineList.RemoveRange(startIndex, endIndex - startIndex + 1);
mLineList.InsertRange(startIndex, newLines);
Debug.Assert(false); // TODO: update display list
mDisplayList.ClearListSegment(startIndex, endIndex - startIndex + 1, newLines.Count);
Debug.Assert(ValidateLineList(), "Display list failed validation");
}
@ -720,7 +721,7 @@ namespace SourceGenWPF {
}
Debug.WriteLine("Removing " + endIndex + " header lines");
mLineList.RemoveRange(0, endIndex);
Debug.Assert(false); // TODO: update display list
mDisplayList.ClearListSegment(0, endIndex, 0);
}
/// <summary>

View File

@ -140,6 +140,9 @@ namespace SourceGenWPF {
/// </summary>
private bool mUseMainAppDomainForPlugins = false;
/// <summary>
/// Code list column numbers.
/// </summary>
public enum CodeListColumn {
Offset = 0, Address, Bytes, Flags, Attributes, Label, Opcode, Operand, Comment,
COUNT // must be last; must equal number of columns
@ -1171,9 +1174,9 @@ namespace SourceGenWPF {
/// Opens the application settings dialog. All changes to settings are made directly
/// to the AppSettings.Global object.
/// </summary>
public void EditSettings() {
public void EditAppSettings() {
EditAppSettings dlg = new EditAppSettings(mMainWin, mMainWin, this,
EditAppSettings.Tab.Unknown, AsmGen.AssemblerInfo.Id.Unknown);
WpfGui.EditAppSettings.Tab.Unknown, AsmGen.AssemblerInfo.Id.Unknown);
dlg.ShowDialog();
}
@ -1250,11 +1253,9 @@ namespace SourceGenWPF {
// does nothing
break;
case CodeListColumn.Label:
#if false
if (editLabelToolStripMenuItem.Enabled) {
EditLabel_Click(sender, e);
if (CanEditLabel()) {
EditLabel();
}
#endif
break;
case CodeListColumn.Opcode:
// File offset should always be valid, since we excluded the EQU
@ -1354,6 +1355,46 @@ namespace SourceGenWPF {
}
}
public bool CanEditLabel() {
if (SelectionAnalysis.mNumItemsSelected != 1) {
return false;
}
EntityCounts counts = SelectionAnalysis.mEntityCounts;
// Single line, code or data.
return (counts.mDataLines > 0 || counts.mCodeLines > 0);
}
public void EditLabel() {
int selIndex = mMainWin.CodeListView_GetFirstSelectedIndex();
int offset = CodeLineList[selIndex].FileOffset;
Anattrib attr = mProject.GetAnattrib(offset);
EditLabel dlg = new EditLabel(mMainWin, attr.Symbol, attr.Address,
mProject.SymbolTable);
if (dlg.ShowDialog() != true) {
return;
}
// NOTE: if label matching is case-insensitive, we want to allow a situation
// where a label is being renamed from "FOO" to "Foo". (We should be able to
// test for object equality on the Symbol.)
if (attr.Symbol != dlg.LabelSym) {
Debug.WriteLine("Changing label at offset +" + offset.ToString("x6"));
// For undo/redo, we want to update the UserLabels value. This may
// be different from the Anattrib symbol, which can have an auto-generated
// value.
Symbol oldUserValue = null;
if (mProject.UserLabels.ContainsKey(offset)) {
oldUserValue = mProject.UserLabels[offset];
}
UndoableChange uc = UndoableChange.CreateLabelChange(offset,
oldUserValue, dlg.LabelSym);
ChangeSet cs = new ChangeSet(uc);
ApplyUndoableChanges(cs);
}
}
public bool CanEditStatusFlags() {
if (SelectionAnalysis.mNumItemsSelected != 1) {
return false;

View File

@ -87,6 +87,9 @@
<Compile Include="WpfGui\EditDefSymbol.xaml.cs">
<DependentUpon>EditDefSymbol.xaml</DependentUpon>
</Compile>
<Compile Include="WpfGui\EditLabel.xaml.cs">
<DependentUpon>EditLabel.xaml</DependentUpon>
</Compile>
<Compile Include="WpfGui\EditProjectProperties.xaml.cs">
<DependentUpon>EditProjectProperties.xaml</DependentUpon>
</Compile>
@ -200,6 +203,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="WpfGui\EditLabel.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="WpfGui\EditProjectProperties.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>

View File

@ -52,23 +52,27 @@ See also https://github.com/fadden/DisasmUiTest
If you don't set DisplayMemberBinding, it will try to ToString() the entire object.
-->
<GridViewColumnCollection x:Key="gvcc">
<GridViewColumn Width="{Binding
<GridViewColumn DisplayMemberBinding="{Binding Offset}" Width="{Binding
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}
}, Path=View.Columns[0].ActualWidth}" DisplayMemberBinding="{Binding Offset}"/>
<GridViewColumn Width="{Binding
}, Path=View.Columns[0].ActualWidth}"/>
<GridViewColumn DisplayMemberBinding="{Binding Addr}" Width="{Binding
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}
}, Path=View.Columns[1].ActualWidth}" DisplayMemberBinding="{Binding Addr}"/>
<GridViewColumn Width="{Binding
}, Path=View.Columns[1].ActualWidth}"/>
<GridViewColumn DisplayMemberBinding="{Binding Bytes}" Width="{Binding
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}
}, Path=View.Columns[2].ActualWidth}" DisplayMemberBinding="{Binding Bytes}"/>
<GridViewColumn Width="{Binding
}, Path=View.Columns[2].ActualWidth}"/>
<GridViewColumn DisplayMemberBinding="{Binding Flags}" Width="{Binding
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}
}, Path=View.Columns[3].ActualWidth}" DisplayMemberBinding="{Binding Flags}"/>
<GridViewColumn Width="{Binding
}, Path=View.Columns[3].ActualWidth}"/>
<GridViewColumn DisplayMemberBinding="{Binding Attr}" Width="{Binding
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}
}, Path=View.Columns[4].ActualWidth}" DisplayMemberBinding="{Binding Attr}"/>
<!-- This column holds the long comment. Leave the width unset. -->
<GridViewColumn Header="two" DisplayMemberBinding="{Binding Path=Comment}"/>
}, Path=View.Columns[4].ActualWidth}"/>
<!-- This column holds the long comment. There's no easy way to set its width, so we
have to let the main window take care of that. (It's tempting to just make its width
very large, but that causes the GridView contents to horizontally scroll independently
of the GridView header when you reach the edge of the "normal" column set.) -->
<GridViewColumn Header="(long comment)" DisplayMemberBinding="{Binding Path=Comment}"
Width="{Binding LongCommentWidth}"/>
</GridViewColumnCollection>
<!-- Template for long lines. This is a modification of the default style, with

View File

@ -72,6 +72,11 @@ namespace SourceGenWPF.WpfGui {
DataContext = this;
}
private void Window_Loaded(object sender, RoutedEventArgs e) {
addrTextBox.SelectAll();
addrTextBox.Focus();
}
private void OkButton_Click(object sender, RoutedEventArgs e) {
if (AddressText.Length == 0) {
Address = -1;
@ -96,11 +101,6 @@ namespace SourceGenWPF.WpfGui {
Asm65.Address.ParseAddress(text, mMaxAddressValue, out int unused);
}
}
private void Window_Loaded(object sender, RoutedEventArgs e) {
addrTextBox.SelectAll();
addrTextBox.Focus();
}
}

View File

@ -0,0 +1,65 @@
<!--
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.EditLabel"
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="Edit Label"
SizeToContent="WidthAndHeight" ResizeMode="NoResize"
ShowInTaskbar="False" WindowStartupLocation="CenterOwner"
Loaded="Window_Loaded">
<Grid Margin="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<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"/>
<TextBlock Name="maxLengthLabel" Text="• Must be 2-32 characters long (or blank to remove)"
Margin="0,3,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">
<StackPanel>
<RadioButton Name="radioButtonLocal" Content="_Local (if possible)" Margin="0,4,0,0"/>
<RadioButton Name="radioButtonGlobal" Content="_Global" Margin="0,4,0,0"/>
<RadioButton Name="radioButtonExport" Content="Global and _exported" Margin="0,4,0,0"/>
</StackPanel>
</GroupBox>
<DockPanel Grid.Column="1" Grid.Row="1" LastChildFill="False">
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="OK" Width="70" IsDefault="True" IsEnabled="{Binding IsValid}"
Click="OkButton_Click"/>
<Button Content="Cancel" Width="70" IsCancel="True" Margin="4,0,0,0"/>
</StackPanel>
</DockPanel>
</Grid>
</Window>

View File

@ -0,0 +1,196 @@
/*
* 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.Windows;
using System.Windows.Media;
namespace SourceGenWPF.WpfGui {
/// <summary>
/// Edit a label.
/// </summary>
public partial class EditLabel : Window, INotifyPropertyChanged {
/// <summary>
/// Symbol object. When the dialog completes successfully,
/// this will have the new symbol, or null if the user deleted the label.
/// </summary>
public Symbol LabelSym { get; private set; }
/// <summary>
/// Address we are editing the label for.
/// </summary>
private int mAddress;
/// <summary>
/// Reference to DisasmProject's SymbolTable.
/// </summary>
private SymbolTable mSymbolTable;
// Dialog label text color, saved off at dialog load time.
private Brush mDefaultLabelColor;
/// <summary>
/// Set to true when input is valid. Controls whether the OK button is enabled.
/// </summary>
public bool IsValid {
get { return mIsValid; }
set {
mIsValid = value;
OnPropertyChanged();
}
}
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;
// INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = "") {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public EditLabel(Window owner, Symbol origSym, int address, SymbolTable symbolTable) {
InitializeComponent();
Owner = owner;
DataContext = this;
LabelSym = origSym;
mAddress = address;
mSymbolTable = symbolTable;
}
private void Window_Loaded(object sender, RoutedEventArgs e) {
mDefaultLabelColor = maxLengthLabel.Foreground;
if (LabelSym == null) {
labelTextBox.Text = string.Empty;
radioButtonLocal.IsChecked = true;
} else {
labelTextBox.Text = LabelSym.Label;
switch (LabelSym.SymbolType) {
case Symbol.Type.LocalOrGlobalAddr:
radioButtonLocal.IsChecked = true;
break;
case Symbol.Type.GlobalAddr:
radioButtonGlobal.IsChecked = true;
break;
case Symbol.Type.GlobalAddrExport:
radioButtonExport.IsChecked = true;
break;
default:
Debug.Assert(false); // WTF
radioButtonLocal.IsChecked = true;
break;
}
}
labelTextBox.SelectAll();
labelTextBox.Focus();
}
private void LabelTextBox_TextChanged(object sender, RoutedEventArgs e) {
string str = labelTextBox.Text;
bool valid = true;
if (str.Length == 1 || str.Length > Asm65.Label.MAX_LABEL_LEN) {
valid = false;
maxLengthLabel.Foreground = Brushes.Red;
} else {
maxLengthLabel.Foreground = mDefaultLabelColor;
}
// Regex never matches on strings of length 0 or 1, but we don't want
// to complain about that since we're already doing that above.
// TODO(maybe): Ideally this wouldn't light up if the only problem was a
// non-alpha first character, since the next test will call that out.
if (str.Length > 1) {
if (!Asm65.Label.ValidateLabel(str)) {
valid = false;
validCharsLabel.Foreground = Brushes.Red;
} else {
validCharsLabel.Foreground = mDefaultLabelColor;
}
} else {
validCharsLabel.Foreground = mDefaultLabelColor;
}
if (str.Length > 0 &&
!((str[0] >= 'A' && str[0] <= 'Z') || (str[0] >= 'a' && str[0] <= 'z') ||
str[0] == '_')) {
// This should have been caught by the regex. We just want to set the
// color on the "first character must be" instruction text.
Debug.Assert(!valid);
firstLetterLabel.Foreground = Brushes.Red;
} else {
firstLetterLabel.Foreground = mDefaultLabelColor;
}
// Refuse to continue if the label already exists. The only exception is if
// it's the same symbol, and it's user-defined. (If they're trying to edit an
// auto label, we want to force them to change the name.)
//
// NOTE: if label matching is case-insensitive, we want to allow a situation
// where a label is being renamed from "FOO" to "Foo". We should be able to
// test for object equality on the Symbol to determine if we're renaming a
// symbol to itself.
if (valid && mSymbolTable.TryGetValue(str, out Symbol sym) &&
(sym != LabelSym || LabelSym.SymbolSource != Symbol.Source.User)) {
valid = false;
notDuplicateLabel.Foreground = Brushes.Red;
} else {
notDuplicateLabel.Foreground = mDefaultLabelColor;
}
IsValid = valid;
}
private void OkButton_Click(object sender, RoutedEventArgs e) {
if (string.IsNullOrEmpty(labelTextBox.Text)) {
LabelSym = null;
} else {
Symbol.Type symbolType;
if (radioButtonLocal.IsChecked == true) {
symbolType = Symbol.Type.LocalOrGlobalAddr;
} else if (radioButtonGlobal.IsChecked == true) {
symbolType = Symbol.Type.GlobalAddr;
} else if (radioButtonExport.IsChecked == true) {
symbolType = Symbol.Type.GlobalAddrExport;
} else {
Debug.Assert(false); // WTF
symbolType = Symbol.Type.LocalOrGlobalAddr;
}
LabelSym = new Symbol(labelTextBox.Text, mAddress, Symbol.Source.User, symbolType);
}
DialogResult = true;
}
}
}

View File

@ -57,6 +57,11 @@ limitations under the License.
<RoutedUICommand x:Key="DebugSourceGenerationTestsCmd" Text="Source Generation Tests..."/>
<RoutedUICommand x:Key="EditAddressCmd" Text="Set Address..."/>
<RoutedUICommand x:Key="EditAppSettingsCmd" Text="Settings..."/>
<RoutedUICommand x:Key="EditLabelCmd" Text="Edit Label...">
<RoutedUICommand.InputGestures>
<KeyGesture>Ctrl+L</KeyGesture>
</RoutedUICommand.InputGestures>
</RoutedUICommand>
<RoutedUICommand x:Key="EditStatusFlagsCmd" Text="Override Status Flags..."/>
<RoutedUICommand x:Key="ExitCmd" Text="Exit"/>
<RoutedUICommand x:Key="HintAsCodeEntryPointCmd" Text="Hint As Code Entry Point"/>
@ -113,6 +118,8 @@ limitations under the License.
Executed="DebugSourceGenerationTestsCmd_Executed"/>
<CommandBinding Command="{StaticResource EditAddressCmd}"
CanExecute="CanEditAddress" Executed="EditAddressCmd_Executed"/>
<CommandBinding Command="{StaticResource EditLabelCmd}"
CanExecute="CanEditLabel" Executed="EditLabelCmd_Executed"/>
<CommandBinding Command="{StaticResource EditStatusFlagsCmd}"
CanExecute="CanEditStatusFlags" Executed="EditStatusFlagsCmd_Executed"/>
<CommandBinding Command="{StaticResource ExitCmd}"
@ -177,24 +184,24 @@ limitations under the License.
<MenuItem Command="Copy"/>
<Separator/>
<MenuItem Command="{StaticResource SelectAllCmd}"/>
<MenuItem Command="Find"/>
<MenuItem Header="Find Next"/>
<MenuItem Header="Go To..."/>
<MenuItem Command="Find"/> <!-- Ctrl+F -->
<MenuItem Header="Find Next"/> <!-- F3 -->
<MenuItem Header="Go To..."/> <!-- Ctrl+G -->
<Separator/>
<MenuItem Header="Edit Header Comment..."/>
<MenuItem Command="Properties" Header="Project Properties..."/>
<MenuItem Header="Toggle Data Scan"/>
<MenuItem Header="Toggle Data Scan"/> <!-- Ctrl+D -->
<Separator/>
<MenuItem Command="{StaticResource EditAppSettingsCmd}"/>
</MenuItem>
<MenuItem Name="actionsMenu" Header="_Actions">
<MenuItem Command="{StaticResource EditAddressCmd}"/>
<MenuItem Command="{StaticResource EditStatusFlagsCmd}"/>
<MenuItem Header="Edit Label..."/>
<MenuItem Header="Edit Operand..."/>
<MenuItem Header="Edit Comment..."/>
<MenuItem Header="Edit Long Comment..."/>
<MenuItem Header="Edit Note..."/>
<MenuItem Command="{StaticResource EditLabelCmd}"/>
<MenuItem Header="Edit Operand..."/> <!-- Ctrl+O -->
<MenuItem Header="Edit Comment..."/> <!-- Ctrl+; -->
<MenuItem Header="Edit Long Comment..."/> <!-- Ctrl+M -->
<MenuItem Header="Edit Note..."/> <!-- Ctrl+N -->
<MenuItem Header="Edit Project Symbol..."/>
<Separator/>
<MenuItem Command="{StaticResource HintAsCodeEntryPointCmd}" InputGestureText="Ctrl+H, Ctrl+C"/>
@ -203,9 +210,9 @@ limitations under the License.
<MenuItem Command="{StaticResource RemoveHintsCmd}" InputGestureText="Ctrl+H, Ctrl+R"/>
<Separator/>
<MenuItem Header="Format Split-Address Table..."/>
<MenuItem Header="Toggle Single-Byte Format"/>
<MenuItem Header="Format As Word"/>
<MenuItem Header="Delete Note/Long Comment"/>
<MenuItem Header="Toggle Single-Byte Format"/> <!-- Ctrl+B -->
<MenuItem Header="Format As Word"/> <!-- Ctrl+W -->
<MenuItem Header="Delete Note/Long Comment"/> <!-- Del -->
<Separator/>
<MenuItem Header="Show Hex Dump"/>
</MenuItem>

View File

@ -48,6 +48,26 @@ namespace SourceGenWPF.WpfGui {
get { return App.ProgramVersion.ToString(); }
}
/// <summary>
/// Width of long comment fields.
/// </summary>
/// <remarks>
/// We need this to be the sum of the leftmost four columns. If we don't set it, the
/// text may be cut off, or -- worse -- extend off the side of the window. If it
/// extends off the end, a scrollbar appears that will scroll the GridView contents
/// without scrolling the GridView headers, which looks terrible.
///
/// XAML doesn't do math, so we need to do it here, whenever the column widths change.
/// </remarks>
public double LongCommentWidth {
get { return mLongCommentWidth; }
set {
mLongCommentWidth = value;
OnPropertyChanged();
}
}
private double mLongCommentWidth;
/// <summary>
/// Reference to controller object.
/// </summary>
@ -101,6 +121,8 @@ namespace SourceGenWPF.WpfGui {
pd = DependencyPropertyDescriptor.FromProperty(
GridViewColumn.WidthProperty, typeof(GridViewColumn));
AddColumnWidthChangeCallback(pd, (GridView)codeListView.View);
UpdateLongCommentWidth();
}
private void AddColumnWidthChangeCallback(PropertyDescriptor pd, DataGrid dg) {
@ -312,6 +334,7 @@ namespace SourceGenWPF.WpfGui {
private void ColumnWidthChanged(object sender, EventArgs e) {
//Debug.WriteLine("Column width change " + sender);
AppSettings.Global.Dirty = true;
UpdateLongCommentWidth();
}
public double LeftPanelWidth {
@ -347,6 +370,16 @@ namespace SourceGenWPF.WpfGui {
}
}
private void UpdateLongCommentWidth() {
GridView gv = (GridView)(codeListView.View);
double totalWidth = 0;
for (int i = (int)MainController.CodeListColumn.Label; i < gv.Columns.Count; i++) {
totalWidth += gv.Columns[i].ActualWidth;
}
LongCommentWidth = totalWidth;
//Debug.WriteLine("Long comment width: " + LongCommentWidth);
}
#endregion Window placement
#region Column widths
@ -461,12 +494,12 @@ namespace SourceGenWPF.WpfGui {
Typeface typeface = new Typeface(codeListView.FontFamily, codeListView.FontStyle,
codeListView.FontWeight, codeListView.FontStretch);
Debug.WriteLine("Default column widths (FUDGE=" + FUDGE + "):");
//Debug.WriteLine("Default column widths (FUDGE=" + FUDGE + "):");
for (int i = 0; i < widths.Length; i++) {
double strLen = Helper.MeasureStringWidth(sSampleStrings[i],
typeface, codeListView.FontSize);
widths[i] = (int)Math.Round(strLen + FUDGE);
Debug.WriteLine(" " + i + ":" + widths[i] + " " + sSampleStrings[i]);
//Debug.WriteLine(" " + i + ":" + widths[i] + " " + sSampleStrings[i]);
}
return widths;
}
@ -706,6 +739,14 @@ namespace SourceGenWPF.WpfGui {
e.CanExecute = mMainCtrl.CanEditAddress();
}
private void CanEditLabel(object sender, CanExecuteRoutedEventArgs e) {
if (mMainCtrl == null || !mMainCtrl.IsProjectOpen()) {
e.CanExecute = false;
return;
}
e.CanExecute = mMainCtrl.CanEditLabel();
}
private void CanEditStatusFlags(object sender, CanExecuteRoutedEventArgs e) {
if (mMainCtrl == null || !mMainCtrl.IsProjectOpen()) {
e.CanExecute = false;
@ -794,7 +835,11 @@ namespace SourceGenWPF.WpfGui {
}
private void EditAppSettingsCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
mMainCtrl.EditSettings();
mMainCtrl.EditAppSettings();
}
private void EditLabelCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
mMainCtrl.EditLabel();
}
private void EditStatusFlagsCmd_Executed(object sender, ExecutedRoutedEventArgs e) {