Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Legacy style scrollbar context menu for easier navigation #495

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
102 changes: 91 additions & 11 deletions src/Notepads/Controls/TextEditor/TextEditorCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public partial class TextEditorCore : RichEditBox
private double _contentScrollViewerVerticalOffsetLastKnownPosition = 0;

private bool _shouldResetScrollViewerToLastKnownPositionAfterRegainingFocus = false;
private bool _shouldResetScrollViewerToLastKnownPositionAfterViewChanged = false;

private bool _loaded = false;

Expand All @@ -66,8 +67,12 @@ public partial class TextEditorCore : RichEditBox
private Canvas _lineNumberCanvas;
private const string LineNumberGridName = "LineNumberGrid";
private Grid _lineNumberGrid;
private const string ContentScrollViewerHorizontalScrollBarName = "HorizontalScrollBar";
private ScrollBar _contentScrollViewerHorizontalScrollBar;
private TextEditorScrollBarContextFlyout _contentScrollViewerHorizontalScrollBarFlyout;
private const string ContentScrollViewerVerticalScrollBarName = "VerticalScrollBar";
private ScrollBar _contentScrollViewerVerticalScrollBar;
private TextEditorScrollBarContextFlyout _contentScrollViewerVerticalScrollBarFlyout;
private const string LineHighlighterAndIndicatorCanvasName = "LineHighlighterAndIndicatorCanvas";
private Canvas _lineHighlighterAndIndicatorCanvas;
private const string LineHighlighterName = "LineHighlighter";
Expand Down Expand Up @@ -133,6 +138,7 @@ public TextEditorCore()

SetDefaultTabStopAndLineSpacing(FontFamily, FontSize);
PointerWheelChanged += OnPointerWheelChanged;
GettingFocus += OnGettingFocus;
LostFocus += OnLostFocus;
Loaded += OnLoaded;

Expand Down Expand Up @@ -171,20 +177,35 @@ protected override void OnApplyTemplate()
_lineIndicator = GetTemplateChild(LineIndicatorName) as Border;

_contentScrollViewer = GetTemplateChild(ContentElementName) as ScrollViewer;
_shouldResetScrollViewerToLastKnownPositionAfterRegainingFocus = true;
_shouldResetScrollViewerToLastKnownPositionAfterViewChanged = true;
_contentScrollViewer.ViewChanging += OnContentScrollViewerViewChanging;
_contentScrollViewer.ViewChanged += OnContentScrollViewerViewChanged;
_contentScrollViewer.SizeChanged += OnContentScrollViewerSizeChanged;

_contentScrollViewer.ApplyTemplate();
var scrollViewerRoot = (FrameworkElement)VisualTreeHelper.GetChild(_contentScrollViewer, 0);
_contentScrollViewerHorizontalScrollBar = (ScrollBar)scrollViewerRoot.FindName(ContentScrollViewerHorizontalScrollBarName);
_contentScrollViewerVerticalScrollBar = (ScrollBar)scrollViewerRoot.FindName(ContentScrollViewerVerticalScrollBarName);
_contentScrollViewerHorizontalScrollBar.ContextFlyout = _contentScrollViewerHorizontalScrollBarFlyout = new TextEditorScrollBarContextFlyout(this, Axis.X);
_contentScrollViewerVerticalScrollBar.ContextFlyout = _contentScrollViewerVerticalScrollBarFlyout = new TextEditorScrollBarContextFlyout(this, Axis.Y);
_contentScrollViewerHorizontalScrollBar.RightTapped += OnContentScrollViewerHorizontalScrollBar_RightTapped;
_contentScrollViewerVerticalScrollBar.RightTapped += OnContentScrollViewerVerticalScrollBar_RightTapped;
_contentScrollViewerVerticalScrollBar.ValueChanged += OnVerticalScrollBarValueChanged;

_lineNumberGrid.SizeChanged += OnLineNumberGridSizeChanged;
_rootGrid.SizeChanged += OnRootGridSizeChanged;
}

private void OnContentScrollViewerVerticalScrollBar_RightTapped(object sender, RightTappedRoutedEventArgs e)
{
_contentScrollViewerVerticalScrollBarFlyout.ClickLocation = e.GetPosition(_contentScrollViewerVerticalScrollBar).Y * (_contentScrollViewer.ScrollableHeight / _contentScrollViewer.ViewportHeight);
}

private void OnContentScrollViewerHorizontalScrollBar_RightTapped(object sender, RightTappedRoutedEventArgs e)
{
_contentScrollViewerHorizontalScrollBarFlyout.ClickLocation = e.GetPosition(_contentScrollViewerHorizontalScrollBar).X * (_contentScrollViewer.ScrollableWidth / _contentScrollViewer.ViewportWidth);
}

private void ResetRootGridClipping()
{
if (!_loaded) return;
Expand All @@ -208,6 +229,7 @@ public void Dispose()
TextChanged -= OnTextChanged;
SelectionChanging -= OnSelectionChanging;
PointerWheelChanged -= OnPointerWheelChanged;
GettingFocus -= OnGettingFocus;
LostFocus -= OnLostFocus;
Loaded -= OnLoaded;

Expand Down Expand Up @@ -368,7 +390,7 @@ private void OnCoreWindowActivated(CoreWindow sender, WindowActivatedEventArgs a
if (args.WindowActivationState == Windows.UI.Core.CoreWindowActivationState.CodeActivated ||
args.WindowActivationState == Windows.UI.Core.CoreWindowActivationState.PointerActivated)
{
_shouldResetScrollViewerToLastKnownPositionAfterRegainingFocus = true;
_shouldResetScrollViewerToLastKnownPositionAfterViewChanged = true;
}
}

Expand All @@ -378,9 +400,9 @@ private void OnLoaded(object sender, RoutedEventArgs _)

ResetRootGridClipping();

if (_shouldResetScrollViewerToLastKnownPositionAfterRegainingFocus)
if (_shouldResetScrollViewerToLastKnownPositionAfterViewChanged)
{
_shouldResetScrollViewerToLastKnownPositionAfterRegainingFocus = false;
_shouldResetScrollViewerToLastKnownPositionAfterViewChanged = false;
_contentScrollViewer.ChangeView(
_contentScrollViewerHorizontalOffsetLastKnownPosition,
_contentScrollViewerVerticalOffsetLastKnownPosition,
Expand All @@ -392,6 +414,17 @@ private void OnLoaded(object sender, RoutedEventArgs _)
if (DisplayLineNumbers) ShowLineNumbers();
}

private void OnGettingFocus(UIElement sender, GettingFocusEventArgs args)
{
if (_shouldResetScrollViewerToLastKnownPositionAfterRegainingFocus)
{
_shouldResetScrollViewerToLastKnownPositionAfterViewChanged = true;
_contentScrollViewer.ChangeView(
_contentScrollViewerHorizontalOffsetLastKnownPosition,
_contentScrollViewerVerticalOffsetLastKnownPosition, null, true);
}
}

private void OnLostFocus(object sender, RoutedEventArgs _)
{
GetScrollViewerPosition(out _contentScrollViewerHorizontalOffsetLastKnownPosition, out _contentScrollViewerVerticalOffsetLastKnownPosition);
Expand Down Expand Up @@ -461,19 +494,23 @@ private void OnContentScrollViewerViewChanging(object sender, ScrollViewerViewCh

private void OnContentScrollViewerViewChanged(object sender, ScrollViewerViewChangedEventArgs _)
{
if (_shouldResetScrollViewerToLastKnownPositionAfterRegainingFocus)
if (_shouldResetScrollViewerToLastKnownPositionAfterRegainingFocus && _shouldResetScrollViewerToLastKnownPositionAfterViewChanged)
{
_shouldResetScrollViewerToLastKnownPositionAfterRegainingFocus = false;
}
else if (_shouldResetScrollViewerToLastKnownPositionAfterViewChanged)
{
_shouldResetScrollViewerToLastKnownPositionAfterViewChanged = false;
var textRange = Document.GetRangeFromPoint(new Point(_contentScrollViewerHorizontalOffsetLastKnownPosition, _contentScrollViewerVerticalOffsetLastKnownPosition), PointOptions.None);
textRange.ScrollIntoView(PointOptions.None);
_contentScrollViewer.ChangeView(
_contentScrollViewerHorizontalOffsetLastKnownPosition,
_contentScrollViewerVerticalOffsetLastKnownPosition,
zoomFactor: null,
disableAnimation: true);
}
else
{
UpdateLineNumbersRendering();
}

UpdateLineNumbersRendering();
}

private void OnContentScrollViewerSizeChanged(object sender, SizeChangedEventArgs _)
Expand Down Expand Up @@ -758,7 +795,7 @@ public bool GoTo(int line)
{
try
{
_shouldResetScrollViewerToLastKnownPositionAfterRegainingFocus = false;
_shouldResetScrollViewerToLastKnownPositionAfterViewChanged = false;
Document.Selection.SetIndex(TextRangeUnit.Paragraph, line, false);
return true;
}
Expand All @@ -770,10 +807,53 @@ public bool GoTo(int line)

public void ResetFocusAndScrollToPreviousPosition()
{
_shouldResetScrollViewerToLastKnownPositionAfterRegainingFocus = true;
_shouldResetScrollViewerToLastKnownPositionAfterViewChanged = true;
base.Focus(FocusState.Programmatic);
}

public void ChangeView(ScrollCommand command, Axis scrollBarAxis, double location = 0)
{
switch (command)
{
case ScrollCommand.ScrollTo:
if (scrollBarAxis == Axis.X)
{
_contentScrollViewerHorizontalOffsetLastKnownPosition = location;
}
else
{
_contentScrollViewerVerticalOffsetLastKnownPosition = location;
}
break;
case ScrollCommand.Top:
_contentScrollViewerVerticalOffsetLastKnownPosition = 0;
break;
case ScrollCommand.Bottom:
_contentScrollViewerVerticalOffsetLastKnownPosition = _contentScrollViewer.ScrollableHeight;
break;
case ScrollCommand.PageUp:
_contentScrollViewerVerticalOffsetLastKnownPosition = _contentScrollViewer.VerticalOffset - _contentScrollViewer.ViewportHeight;
break;
case ScrollCommand.PageDown:
_contentScrollViewerVerticalOffsetLastKnownPosition = _contentScrollViewer.VerticalOffset + _contentScrollViewer.ViewportHeight;
break;
case ScrollCommand.LeftEdge:
_contentScrollViewerHorizontalOffsetLastKnownPosition = 0;
break;
case ScrollCommand.RightEdge:
_contentScrollViewerHorizontalOffsetLastKnownPosition = _contentScrollViewer.ScrollableWidth;
break;
case ScrollCommand.PageLeft:
_contentScrollViewerHorizontalOffsetLastKnownPosition = _contentScrollViewer.HorizontalOffset - _contentScrollViewer.ViewportWidth;
break;
case ScrollCommand.PageRight:
_contentScrollViewerHorizontalOffsetLastKnownPosition = _contentScrollViewer.HorizontalOffset + _contentScrollViewer.ViewportWidth;
break;
}

_shouldResetScrollViewerToLastKnownPositionAfterRegainingFocus = true;
}

private void SetDefaultTabStopAndLineSpacing(FontFamily font, double fontSize)
{
Document.DefaultTabStop = (float)FontUtility.GetTextSize(font, fontSize, "text").Width;
Expand Down