mirror of
https://github.com/fadden/6502bench.git
synced 2024-12-24 07:29:42 +00:00
Improve save & restore of top line
Whenever the display list gets regenerated, we need to restore the code list view scroll position to the previous location in the file. This gets tricky when multiple lines are appearing or disappearing. We were saving the file offset of the line, but that works poorly when there's a multi-line comment associated with that offset, because we end up scrolling to the top of the comment whenever any part of the comment is at the top of the screen. We now track the file offset and the number of lines we were from the top of that offset's content. This works well unless we remove a lot of lines. If the adjusted line index would put us into a different file offset, we punt and just scroll to the top of the item. Also, fix a crasher in Edit Note. Also, fix behavior when the list shrinks while a line near the end of the file is selected. Also, change a few instances of "Color.FromArgb(0,0,0,0)" to use a common constant.
This commit is contained in:
parent
0ff2ebefdf
commit
a0dca6a5be
@ -24,6 +24,8 @@ namespace CommonWPF {
|
||||
/// Miscellaneous helper functions.
|
||||
/// </summary>
|
||||
public static class Helper {
|
||||
public static Color ZeroColor = Color.FromArgb(0, 0, 0, 0);
|
||||
|
||||
/// <summary>
|
||||
/// Measures the size of a string when rendered with the specified parameters. Uses
|
||||
/// the current culture, left-to-right flow, and 1 pixel per DIP.
|
||||
|
@ -303,7 +303,7 @@ namespace SourceGenWPF {
|
||||
" new=" + newCount + " (mList.Count=" + mList.Count + ")");
|
||||
|
||||
Debug.Assert(startIndex >= 0 && startIndex < mList.Count);
|
||||
Debug.Assert(oldCount > 0 && startIndex + oldCount < mList.Count);
|
||||
Debug.Assert(oldCount > 0 && startIndex + oldCount <= mList.Count);
|
||||
Debug.Assert(newCount >= 0);
|
||||
|
||||
// Remove the old elements to clear them.
|
||||
@ -358,7 +358,7 @@ namespace SourceGenWPF {
|
||||
|
||||
public int ListIndex { get; set; } = -1;
|
||||
|
||||
private static Color NoColor = Color.FromArgb(0, 0, 0, 0);
|
||||
private static Color NoColor = CommonWPF.Helper.ZeroColor;
|
||||
|
||||
|
||||
// Private constructor -- create instances with factory methods.
|
||||
@ -448,6 +448,10 @@ namespace SourceGenWPF {
|
||||
newParts.HasAddrLabelHighlight = false;
|
||||
return newParts;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return "[Parts: index=" + ListIndex + " off=" + Offset + "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,8 +111,12 @@ namespace SourceGenWPF {
|
||||
this[parts.ListIndex] = true;
|
||||
}
|
||||
foreach (DisplayList.FormattedParts parts in e.RemovedItems) {
|
||||
Debug.Assert(parts.ListIndex >= 0 && parts.ListIndex < mSelection.Length);
|
||||
this[parts.ListIndex] = false;
|
||||
Debug.Assert(parts.ListIndex >= 0);
|
||||
if (parts.ListIndex < mSelection.Length) {
|
||||
this[parts.ListIndex] = false;
|
||||
} else {
|
||||
Debug.WriteLine("Attempted to remove selected item off end of list: " + parts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,6 +75,8 @@ namespace SourceGenWPF {
|
||||
// Extremely-negative offset value ensures it's at the very top.
|
||||
public const int HEADER_COMMENT_OFFSET = int.MinValue + 1;
|
||||
|
||||
// These need to be bit flags so we can record which parts associated with a
|
||||
// given offset are selected.
|
||||
[FlagsAttribute]
|
||||
public enum Type {
|
||||
Unclassified = 0,
|
||||
@ -131,7 +133,7 @@ namespace SourceGenWPF {
|
||||
public FormattedParts Parts { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Background color, used for notes.
|
||||
/// Background color, used for Notes.
|
||||
/// </summary>
|
||||
public Color BackgroundColor { get; set; }
|
||||
|
||||
@ -213,11 +215,28 @@ namespace SourceGenWPF {
|
||||
|
||||
private List<Tag> mSelectionTags = new List<Tag>();
|
||||
|
||||
private class Top {
|
||||
// File offset of line.
|
||||
public int FileOffset { get; private set; }
|
||||
// Number of lines between the first line at the specified offset and the
|
||||
// target line.
|
||||
public int LineDelta { get; private set; }
|
||||
|
||||
public Top(int fileOffset, int lineDelta) {
|
||||
FileOffset = fileOffset;
|
||||
LineDelta = lineDelta;
|
||||
Debug.WriteLine("New Top: " + this);
|
||||
}
|
||||
public override string ToString() {
|
||||
return "[Top: off=+" + FileOffset.ToString("x6") + " delta=" + LineDelta + "]";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is a place to save the file offset associated with the ListView's
|
||||
/// TopItem, so we can position the list appropriately.
|
||||
/// </summary>
|
||||
private int mTopOffset;
|
||||
private Top mTopPosition;
|
||||
|
||||
// Use Generate().
|
||||
private SavedSelection() { }
|
||||
@ -230,12 +249,18 @@ namespace SourceGenWPF {
|
||||
/// </summary>
|
||||
/// <param name="dl">Display list, with list of Lines.</param>
|
||||
/// <param name="sel">Bit vector specifying which lines are selected.</param>
|
||||
/// <param name="topIndex">Index of line that appears at the top of the list
|
||||
/// control.</param>
|
||||
/// <returns>New SavedSelection object.</returns>
|
||||
public static SavedSelection Generate(LineListGen dl, DisplayListSelection sel,
|
||||
int topOffset) {
|
||||
int topIndex) {
|
||||
SavedSelection savedSel = new SavedSelection();
|
||||
//Debug.Assert(topOffset >= 0);
|
||||
savedSel.mTopOffset = topOffset;
|
||||
|
||||
int topOffset = dl[topIndex].FileOffset;
|
||||
int firstIndex = dl.FindLineIndexByOffset(topOffset);
|
||||
Debug.Assert(topIndex >= firstIndex);
|
||||
savedSel.mTopPosition = new Top(topOffset, topIndex - firstIndex);
|
||||
|
||||
List<Line> lineList = dl.mLineList;
|
||||
Debug.Assert(lineList.Count == sel.Length);
|
||||
@ -313,7 +338,7 @@ namespace SourceGenWPF {
|
||||
|
||||
// If a line encompassing this offset was at the top of the ListView
|
||||
// control before, use this line's index as the top.
|
||||
if (topIndex < 0 && lineList[lineIndex].Contains(mTopOffset)) {
|
||||
if (topIndex < 0 && lineList[lineIndex].Contains(mTopPosition.FileOffset)) {
|
||||
topIndex = lineIndex;
|
||||
}
|
||||
|
||||
@ -336,14 +361,29 @@ namespace SourceGenWPF {
|
||||
|
||||
// Continue search for topIndex, if necessary.
|
||||
while (topIndex < 0 && lineIndex < lineList.Count) {
|
||||
if (lineList[lineIndex].Contains(mTopOffset)) {
|
||||
if (lineList[lineIndex].Contains(mTopPosition.FileOffset)) {
|
||||
topIndex = lineIndex;
|
||||
break;
|
||||
}
|
||||
lineIndex++;
|
||||
}
|
||||
Debug.WriteLine("TopOffset +" + mTopOffset.ToString("x6") +
|
||||
" --> index " + topIndex);
|
||||
Debug.WriteLine("TopOffset " + mTopPosition + " --> index " + topIndex);
|
||||
|
||||
// Adjust position within an element. This is necessary so we don't jump to
|
||||
// the top of multi-line long comments or notes whenever any part of that
|
||||
// comment or note is at the top of the list.
|
||||
if (topIndex >= 0 && mTopPosition.LineDelta > 0) {
|
||||
int adjIndex = topIndex + mTopPosition.LineDelta;
|
||||
if (adjIndex >= lineList.Count ||
|
||||
lineList[adjIndex].FileOffset != mTopPosition.FileOffset) {
|
||||
Debug.WriteLine("Can't adjust top position");
|
||||
// can't adjust; maybe they deleted several lines from comment
|
||||
} else {
|
||||
topIndex = adjIndex;
|
||||
Debug.WriteLine("Top index adjusted to " + adjIndex);
|
||||
}
|
||||
}
|
||||
|
||||
if (topIndex < 0) {
|
||||
// This can happen if you delete the header comment while scrolled
|
||||
// to the top of the list.
|
||||
@ -775,7 +815,7 @@ namespace SourceGenWPF {
|
||||
out MultiLineComment headerComment)) {
|
||||
List<string> formatted = headerComment.FormatText(formatter, string.Empty);
|
||||
StringListToLines(formatted, Line.HEADER_COMMENT_OFFSET, Line.Type.LongComment,
|
||||
Color.FromArgb(0, 0, 0, 0), tmpLines);
|
||||
CommonWPF.Helper.ZeroColor, tmpLines);
|
||||
}
|
||||
|
||||
// Format symbols.
|
||||
|
@ -697,8 +697,7 @@ namespace SourceGenWPF {
|
||||
mReanalysisTimer.StartTask("Save selection");
|
||||
int topItemIndex = mMainWin.CodeListView_GetTopIndex();
|
||||
LineListGen.SavedSelection savedSel = LineListGen.SavedSelection.Generate(
|
||||
CodeLineList, mMainWin.CodeDisplayList.SelectedIndices,
|
||||
CodeLineList[topItemIndex].FileOffset);
|
||||
CodeLineList, mMainWin.CodeDisplayList.SelectedIndices, topItemIndex);
|
||||
//savedSel.DebugDump();
|
||||
|
||||
// Clear this so we don't try to fiddle with it later.
|
||||
@ -1692,7 +1691,7 @@ namespace SourceGenWPF {
|
||||
|
||||
MultiLineComment oldNote;
|
||||
if (!mProject.Notes.TryGetValue(offset, out oldNote)) {
|
||||
oldNote = new MultiLineComment(string.Empty);
|
||||
oldNote = null;
|
||||
}
|
||||
EditNote dlg = new EditNote(mMainWin, oldNote);
|
||||
dlg.ShowDialog();
|
||||
|
@ -62,7 +62,7 @@ namespace SourceGenWPF {
|
||||
Text = text;
|
||||
BoxMode = false;
|
||||
MaxWidth = 80;
|
||||
BackgroundColor = Color.FromArgb(0, 0, 0, 0);
|
||||
BackgroundColor = CommonWPF.Helper.ZeroColor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -70,7 +70,7 @@ namespace SourceGenWPF {
|
||||
return obj is Location && this == (Location)obj;
|
||||
}
|
||||
public override int GetHashCode() {
|
||||
return Offset + (IsNote ? 65536 : 0);
|
||||
return Offset + (IsNote ? (1<<24) : 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ namespace SourceGenWPF.Tests {
|
||||
public Color Color { get; private set; }
|
||||
public bool HasColor { get { return Color.A != 0; } }
|
||||
|
||||
public ProgressMessage(string msg) : this(msg, Color.FromArgb(0, 0, 0, 0)) { }
|
||||
public ProgressMessage(string msg) : this(msg, CommonWPF.Helper.ZeroColor) { }
|
||||
|
||||
public ProgressMessage(string msg, Color color) {
|
||||
Text = msg;
|
||||
|
@ -32,9 +32,9 @@ limitations under the License.
|
||||
<StackPanel Margin="0,16,0,0" Orientation="Horizontal">
|
||||
<Button Name="saveButton" Width="120"
|
||||
Content="_Save & Continue" Click="SaveButton_Click"/>
|
||||
<Button Name="dontSaveButton" Width="120" Margin="8,0,0,0"
|
||||
<Button Name="dontSaveButton" Width="120" Margin="12,0,0,0"
|
||||
Content="_Discard & Continue" Click="DontSaveButton_Click"/>
|
||||
<Button Name="cancelButton" Width="120" Margin="8,0,0,0"
|
||||
<Button Name="cancelButton" Width="120" Margin="12,0,0,0"
|
||||
Content="Cancel" IsCancel="True"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
@ -53,7 +53,7 @@ namespace SourceGenWPF.WpfGui {
|
||||
None = 0, Green, Blue, Yellow, Pink, Orange
|
||||
}
|
||||
private static Color[] sColors = new Color[] {
|
||||
Color.FromArgb(0, 0, 0, 0), // no highlight
|
||||
CommonWPF.Helper.ZeroColor, // no highlight
|
||||
Colors.LightGreen,
|
||||
Colors.LightBlue,
|
||||
Colors.Yellow, //LightGoldenrodYellow,
|
||||
@ -74,7 +74,11 @@ namespace SourceGenWPF.WpfGui {
|
||||
Owner = owner;
|
||||
DataContext = this;
|
||||
|
||||
Note = note;
|
||||
if (note == null) {
|
||||
Note = new MultiLineComment(string.Empty);
|
||||
} else {
|
||||
Note = note;
|
||||
}
|
||||
|
||||
mColorButtons = new RadioButton[] {
|
||||
colorDefaultRadio,
|
||||
@ -102,6 +106,7 @@ namespace SourceGenWPF.WpfGui {
|
||||
}
|
||||
}
|
||||
|
||||
inputTextBox.Focus();
|
||||
}
|
||||
|
||||
// Handle Ctrl+Enter as a way to close the dialog, since plain Enter just
|
||||
|
@ -772,7 +772,9 @@ namespace SourceGenWPF.WpfGui {
|
||||
}
|
||||
|
||||
public int CodeListView_GetTopIndex() {
|
||||
return codeListView.GetTopItemIndex();
|
||||
int index = codeListView.GetTopItemIndex();
|
||||
Debug.Assert(index >= 0);
|
||||
return index;
|
||||
}
|
||||
|
||||
public void CodeListView_SetTopIndex(int index) {
|
||||
|
Loading…
Reference in New Issue
Block a user