-
Notifications
You must be signed in to change notification settings - Fork 735
Fixes #3823 - Upgrades TextView to use View's modern scrolling infrastructure
#4407
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
base: v2_develop
Are you sure you want to change the base?
Changes from 7 commits
817b90a
bb536e2
424ad9c
56ee4fd
114a271
82344d4
23f4f29
5a8f269
26b3fc9
4fe8df3
fca6048
562ec7b
9b4f336
9d060ce
1cf47f6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -770,7 +770,13 @@ public int LeftColumn | |||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| _leftColumn = Math.Max (Math.Min (value, Maxlength - 1), 0); | ||||||||||||||||||||||||||||||
| int clampedValue = Math.Max (Math.Min (value, Maxlength - 1), 0); | ||||||||||||||||||||||||||||||
| _leftColumn = clampedValue; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (IsInitialized && Viewport.X != _leftColumn) | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| Viewport = Viewport with { X = _leftColumn }; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
@@ -966,7 +972,16 @@ public override string Text | |||||||||||||||||||||||||||||
| public int TopRow | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| get => _topRow; | ||||||||||||||||||||||||||||||
| set => _topRow = Math.Max (Math.Min (value, Lines - 1), 0); | ||||||||||||||||||||||||||||||
| set | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| int clampedValue = Math.Max (Math.Min (value, Lines - 1), 0); | ||||||||||||||||||||||||||||||
| _topRow = clampedValue; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (IsInitialized && Viewport.Y != _topRow) | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| Viewport = Viewport with { Y = _topRow }; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||||
|
|
@@ -1004,6 +1019,13 @@ public bool WordWrap | |||||||||||||||||||||||||||||
| _model = _wrapManager.Model; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| // Update horizontal scrollbar AutoShow based on WordWrap | ||||||||||||||||||||||||||||||
| if (IsInitialized) | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| HorizontalScrollBar.AutoShow = !_wordWrap; | ||||||||||||||||||||||||||||||
| UpdateContentSize (); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| SetNeedsDraw (); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
@@ -1777,6 +1799,12 @@ public virtual void OnContentsChanged () | |||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| ProcessInheritsPreviousScheme (CurrentRow, CurrentColumn); | ||||||||||||||||||||||||||||||
| ProcessAutocomplete (); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| // Update content size when content changes | ||||||||||||||||||||||||||||||
| if (IsInitialized) | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| UpdateContentSize (); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| /// <inheritdoc/> | ||||||||||||||||||||||||||||||
|
|
@@ -2139,12 +2167,22 @@ public void ScrollTo (int idx, bool isRow = true) | |||||||||||||||||||||||||||||
| if (isRow) | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| _topRow = Math.Max (idx > _model.Count - 1 ? _model.Count - 1 : idx, 0); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (IsInitialized && Viewport.Y != _topRow) | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| Viewport = Viewport with { Y = _topRow }; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| else if (!_wordWrap) | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| int maxlength = | ||||||||||||||||||||||||||||||
| _model.GetMaxVisibleLine (_topRow, _topRow + Viewport.Height, TabWidth); | ||||||||||||||||||||||||||||||
| _leftColumn = Math.Max (!_wordWrap && idx > maxlength - 1 ? maxlength - 1 : idx, 0); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (IsInitialized && Viewport.X != _leftColumn) | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| Viewport = Viewport with { X = _leftColumn }; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| SetNeedsDraw (); | ||||||||||||||||||||||||||||||
|
|
@@ -2342,6 +2380,12 @@ private void Adjust () | |||||||||||||||||||||||||||||
| need = true; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| // Sync Viewport with the internal scroll position | ||||||||||||||||||||||||||||||
| if (IsInitialized && (_leftColumn != Viewport.X || _topRow != Viewport.Y)) | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| Viewport = new Rectangle (_leftColumn, _topRow, Viewport.Width, Viewport.Height); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (need) | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| if (_wrapNeeded) | ||||||||||||||||||||||||||||||
|
|
@@ -4652,12 +4696,72 @@ private void TextView_Initialized (object sender, EventArgs e) | |||||||||||||||||||||||||||||
| App?.Popover?.Register (ContextMenu); | ||||||||||||||||||||||||||||||
| KeyBindings.Add (ContextMenu.Key, Command.Context); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| // Configure ScrollBars to use modern View scrolling infrastructure | ||||||||||||||||||||||||||||||
| ConfigureScrollBars (); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| OnContentsChanged (); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||||
| /// Configures the ScrollBars to work with the modern View scrolling system. | ||||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||||
| private void ConfigureScrollBars () | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| // Subscribe to ViewportChanged to sync internal scroll fields | ||||||||||||||||||||||||||||||
| ViewportChanged += TextView_ViewportChanged; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| // Vertical ScrollBar: AutoShow enabled by default as per requirements | ||||||||||||||||||||||||||||||
| VerticalScrollBar.AutoShow = true; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| // Horizontal ScrollBar: AutoShow tracks WordWrap as per requirements | ||||||||||||||||||||||||||||||
| HorizontalScrollBar.AutoShow = !WordWrap; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| private void TextView_ViewportChanged (object? sender, DrawEventArgs e) | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| // Sync internal scroll position fields with Viewport | ||||||||||||||||||||||||||||||
| // Only update if values actually changed to prevent infinite loops | ||||||||||||||||||||||||||||||
| if (_topRow != Viewport.Y) | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| _topRow = Viewport.Y; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (_leftColumn != Viewport.X) | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| _leftColumn = Viewport.X; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||||
| /// Updates the content size based on the text model dimensions. | ||||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||||
| private void UpdateContentSize () | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| int contentHeight = Math.Max (_model.Count, 1); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| // For horizontal size: if word wrap is enabled, content width equals viewport width | ||||||||||||||||||||||||||||||
| // Otherwise, calculate the maximum line width (but only if we have a reasonable viewport) | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
| // Otherwise, calculate the maximum line width (but only if we have a reasonable viewport) | |
| // Otherwise, calculate the maximum line width |
Outdated
Copilot
AI
Nov 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Misleading comment: the comment claims to "cache the current value to avoid recalculating on every call" but no caching is actually implemented. The method calls _model.GetMaxVisibleLine() on every invocation. Either implement caching or remove the misleading comment.
| // Cache the current value to avoid recalculating on every call |
Outdated
Copilot
AI
Nov 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both branches of this 'if' statement write to the same variable - consider using '?' to express intent better.
| if (_wordWrap) | |
| { | |
| // Word wrap: content width follows viewport width | |
| contentWidth = Math.Max (Viewport.Width, 1); | |
| } | |
| else | |
| { | |
| // No word wrap: calculate max line width | |
| // Cache the current value to avoid recalculating on every call | |
| contentWidth = Math.Max (_model.GetMaxVisibleLine (0, _model.Count, TabWidth), 1); | |
| } | |
| contentWidth = _wordWrap | |
| ? Math.Max (Viewport.Width, 1) | |
| : Math.Max (_model.GetMaxVisibleLine (0, _model.Count, TabWidth), 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Performance concern:
UpdateContentSize()is called on every content change (each keystroke), which triggers_model.GetMaxVisibleLine(0, _model.Count, TabWidth)- a potentially expensive O(n) operation that scans all lines. For large documents, this could cause noticeable lag during typing. Consider throttling or debouncing this call, or caching the max line width and only updating it when necessary.