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

Fixes #2489. Create new ScrollBar based on a new Scroll and remove ScrollBarView/ScrollView #3498

Closed
wants to merge 105 commits into from
Closed
Show file tree
Hide file tree
Changes from 58 commits
Commits
Show all changes
105 commits
Select commit Hold shift + click to select a range
478c93d
Create a Scroll class with unit tests and use case.
BDisp May 23, 2024
84c69f0
Remove unnecessary _sliderContainer view.
BDisp May 24, 2024
4cb27fc
Rename to Scroll_ prefix on the Scroll event methods.
BDisp May 24, 2024
46d1749
Tweaks and suggestions
tig May 24, 2024
57d4f0d
More autosize related tweaks
tig May 24, 2024
d6a183c
Merge pull request #180 from tig/BDisp-v2_2489-tig-1
BDisp May 24, 2024
24e4f65
Remove unnecessary ClearOnVisibleFalse property.
BDisp May 24, 2024
de6d276
Remove unneeded comments.
BDisp May 24, 2024
86e0db2
Add mouse wheel.
BDisp May 24, 2024
30be052
Ensure the Position is valid if the slider is at end.
BDisp May 24, 2024
8c617f3
Fixes NumericUpDown resize when number of characters grows.
BDisp May 24, 2024
365f889
Added more tweaks.
BDisp May 24, 2024
d5b98a1
Suggestions and questions
tig May 25, 2024
dc9d384
Merge pull request #181 from tig/BDisp-v2_2489-tig-2
BDisp May 25, 2024
ee47e75
Change Parent to SuperView.
BDisp May 25, 2024
d4e6ae6
Resolving merge conflicts.
BDisp Jun 12, 2024
4e57840
Fix merge errors.
BDisp Jun 12, 2024
057e89c
Merge branch 'v2_develop' into v2_2489_scroll-scrollbar-new
BDisp Jun 21, 2024
7489d6c
Replace local var with private getter field.
BDisp Jun 22, 2024
1e9e27a
Only raises PositionChanging and PositionChanged if position has chan…
BDisp Jun 22, 2024
becad1d
Add slider highlight effect.
BDisp Jun 22, 2024
5d2120e
Replace private _barSize with local variables barSize and improving p…
BDisp Jun 23, 2024
5c6b39b
Removed unnecessary methods and now unit test pass.
BDisp Jun 23, 2024
d44efe3
Setting entire ColorScheme attributes.
BDisp Jun 24, 2024
5cc3afb
Merge branch 'v2_2489_scroll-scrollbar-new' of github.com:BDisp/Termi…
tig Jun 24, 2024
9ed6cf7
Merge branch 'v2_develop' into v2_2489_scroll-scrollbar-new
BDisp Jul 11, 2024
f9aa619
Fix merge errors.
BDisp Jul 11, 2024
e5f1476
Merge branch 'v2_develop' into v2_2489_scroll-scrollbar-new
tig Jul 11, 2024
4a68fc0
Resolving merge conflicts.
BDisp Aug 14, 2024
9b4269e
Fix merge errors.
BDisp Aug 14, 2024
91e4abf
Ensures Position set before call AdjustSlider and
BDisp Aug 14, 2024
c20b733
Merge branch 'v2_develop' into v2_2489_scroll-scrollbar-new
BDisp Aug 14, 2024
b488796
Move Scroll.cs to the Scroll folder.
BDisp Aug 14, 2024
fa6fb11
Add internal ScrollSlider class.
BDisp Aug 14, 2024
4e22706
Using overridden methods instead of events.
BDisp Aug 14, 2024
3317c50
Moving slider code to his class.
BDisp Aug 16, 2024
b025beb
Rename id to scrollSlider to avoid conflict with the Slider view.
BDisp Aug 16, 2024
9b89657
Fix scroll slider when moving mouse outside the host.
BDisp Aug 16, 2024
3386d06
Ensure correct Width/Height when orientation is changed.
BDisp Aug 16, 2024
e59c02a
Rename to AdjustScroll method.
BDisp Aug 19, 2024
ffa08b8
Merge branch 'v2_develop' into v2_2489_scroll-scrollbar-new
BDisp Aug 19, 2024
7e3a3b2
Fixes #3679. WantContinuousButtonPressed mustn't force calling GrabMo…
BDisp Aug 21, 2024
6add7a1
Merge branch 'v2_develop' into v2_2489_scroll-scrollbar-new
BDisp Aug 21, 2024
c587cb9
Merge branch 'v2_3679_want-continuous-pressed-fix' into v2_2489_scrol…
BDisp Aug 21, 2024
8188822
Ensures slider to have a length proportional to the bar size.
BDisp Aug 21, 2024
92e067e
Prevents continuous mouse button pressed from processing mouse event …
BDisp Aug 21, 2024
5e7bb7b
Starting implementing ScrollBar.
BDisp Aug 23, 2024
479ff3d
Merge branch 'v2_develop' into v2_2489_scroll-scrollbar-new
BDisp Aug 23, 2024
ecc44fc
Merge branch 'v2_develop' into v2_2489_scroll-scrollbar-new
BDisp Aug 23, 2024
14ed92e
Restore color scheme on mouse leave no matter the button.
BDisp Aug 23, 2024
cb7bc94
Ensures accurate calculation if is hosted by a ScrollBar before initi…
BDisp Aug 24, 2024
d47188f
Consolidating GetPositionFromSliderLocation and GetSliderLocationDime…
BDisp Aug 25, 2024
7a1eb98
Code cleanup.
BDisp Aug 25, 2024
71d558f
Remove _wasSliderLayoutComplete field.
BDisp Aug 25, 2024
d3ab81e
Add ScrollBar unit tests and code cleanup.
BDisp Aug 25, 2024
a343fd0
Add ScrollButton unit test and code cleanup.
BDisp Aug 26, 2024
ae3fcef
Remove host parameter from scroll classes.
BDisp Aug 26, 2024
1ccd548
Merge branch 'v2_develop' into v2_2489_scroll-scrollbar-new
BDisp Sep 2, 2024
a83b8f1
Merge branch 'v2_develop' into v2_2489_scroll-scrollbar-new
BDisp Sep 2, 2024
e489146
Replaces VariationMode with NavigationDirection enum.
BDisp Sep 2, 2024
27aa591
Remove Virtual.
BDisp Sep 2, 2024
7343832
Replace with SuperViewAsScrollBar.
BDisp Sep 2, 2024
b16b463
Doc changes addressed by @tig.
BDisp Sep 2, 2024
3e7d950
Merge branch 'v2_develop' into v2_2489_scroll-scrollbar-new
BDisp Sep 2, 2024
11fc893
Remove commented code.
BDisp Sep 2, 2024
f0d2bbe
Rename to SuperViewAsScroll.
BDisp Sep 2, 2024
1804d08
Add private BarSize method.
BDisp Sep 3, 2024
bf4b7bd
Merge branch 'v2_develop' into v2_2489_scroll-scrollbar-new
BDisp Sep 3, 2024
c43de60
BarSize should use Viewport.
BDisp Sep 3, 2024
70b3be2
The barSize should use the Scroll Viewport.
BDisp Sep 3, 2024
6c972c6
Add AutoHideScrollBar and ShowScrollIndicator properties.
BDisp Sep 3, 2024
5279af1
Merge branch 'v2_2489_scroll-scrollbar-new' of tig:BDisp/Terminal.Gui…
tig Sep 3, 2024
e2a2aa1
Upgraded CharMap to use new ScrollBar
tig Sep 3, 2024
68b0352
Merge pull request #194 from tig/BDisp-v2_2489_scroll-scrollbar-new
BDisp Sep 3, 2024
cb1c793
Code cleanup and API doc improvements
tig Sep 3, 2024
c48f6d9
Merge branch 'v2_2489_scroll-scrollbar-new' into BDisp-v2_2489_scroll…
BDisp Sep 4, 2024
7983500
Fix @tig branch errors.
BDisp Sep 4, 2024
9075aca
Using Visible instead of ShowScrollIndicator.
BDisp Sep 4, 2024
3bd4638
I think this was already done before.
BDisp Sep 4, 2024
da85d58
Rename to start and end.
BDisp Sep 4, 2024
20370c4
Remove comment.
BDisp Sep 4, 2024
f54ded3
Add KeepContentInAllViewport to Scroll.
BDisp Sep 4, 2024
07d7162
Prevent Size being negative.
BDisp Sep 4, 2024
14e2e3c
Fix some KeepContentInAllViewport bugs.
BDisp Sep 4, 2024
dbbde3e
Using GetContentSize.
BDisp Sep 4, 2024
bf3e9b2
Fixes #3729. ProcessContinuousButtonPressedAsync is using a stale Mou…
BDisp Sep 5, 2024
06e9910
Merge branch 'v2_3729_windowsdriver-continuous-mouse-pressed-fix' int…
BDisp Sep 5, 2024
6b39670
Merge branch 'v2_develop' into v2_2489_scroll-scrollbar-new
BDisp Sep 5, 2024
cccbbc2
Typo.
BDisp Sep 5, 2024
8d346a8
Implement @tig scroll bars and fix some bugs.
BDisp Sep 5, 2024
84225fc
Fix unit test.
BDisp Sep 5, 2024
bd51356
Add unit test for KeepContentInAllViewport as false.
BDisp Sep 5, 2024
66ec2de
Fix more unit tests that were used with KeepContentInAllViewport as t…
BDisp Sep 5, 2024
630638e
Fix nullable warnings.
BDisp Sep 5, 2024
ae7a86f
Fix ScrollBar that was returning more 2 position at end.
BDisp Sep 6, 2024
c5e886f
Manipulate ViewportSettings with ScrollBars.
BDisp Sep 6, 2024
03dac3e
Merged bdisp latest.
tig Sep 7, 2024
b19437d
Merge pull request #197 from tig/BDisp-v2_2489_scroll-tig-builtin
BDisp Sep 7, 2024
060f915
Merge branch 'v2_2489_scroll-scrollbar-new' of tig:BDisp/Terminal.Gui…
tig Sep 8, 2024
38c604e
More CharMap tweaks
tig Sep 8, 2024
0f3c1ee
Merge pull request #198 from tig/BDisp-v2_2489_scroll-tig-builtin
BDisp Sep 9, 2024
0c55203
Merge branch 'v2_2489_scroll-scrollbar-new' of tig:BDisp/Terminal.Gui…
tig Sep 9, 2024
f4931c2
API doc and overview improvements
tig Sep 9, 2024
f8b2d02
Doc'd samples
tig Sep 9, 2024
0bafe6e
Merge pull request #199 from tig/BDisp-v2_2489_scroll-tig-builtin
BDisp Sep 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
214 changes: 214 additions & 0 deletions Terminal.Gui/Views/Scroll/Scroll.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
#nullable enable

using System.ComponentModel;

namespace Terminal.Gui;

/// <summary>
/// Provides a proportional control for scrolling through content. Used within a <see cref="ScrollBar"/>.
/// </summary>
public class Scroll : View
BDisp marked this conversation as resolved.
Show resolved Hide resolved
{
/// <inheritdoc/>
public Scroll ()
{
_slider = new ();
Add (_slider);

WantContinuousButtonPressed = true;
CanFocus = false;
Orientation = Orientation.Vertical;

Width = Dim.Auto (DimAutoStyle.Content, 1);
Height = Dim.Auto (DimAutoStyle.Content, 1);
tig marked this conversation as resolved.
Show resolved Hide resolved
}

internal readonly ScrollSlider _slider;
private Orientation _orientation;
private int _position;
private int _size;

/// <inheritdoc/>
public override void EndInit ()
BDisp marked this conversation as resolved.
Show resolved Hide resolved
{
base.EndInit ();

AdjustScroll ();
}

/// <summary>
/// Gets or sets if the Scroll is oriented vertically or horizontally.
/// </summary>
public Orientation Orientation
{
get => _orientation;
set
{
_orientation = value;
AdjustScroll ();
}
}

/// <summary>
/// Gets or sets the position of the start of the Scroll slider, relative to <see cref="Size"/>.
/// </summary>
public int Position
{
get => _position;
set
{
if (value == _position || value < 0)
{
return;
}

if (SupView is { IsInitialized: false })
{
// Ensures a more exactly calculation
SetRelativeLayout (SupView.Frame.Size);
}

int barSize = Orientation == Orientation.Vertical ? GetContentSize ().Height : GetContentSize ().Width;

if (value + barSize > Size)
{
return;
}

CancelEventArgs<int> args = OnPositionChanging (_position, value);

if (args.Cancel)
{
return;
}

_position = value;

AdjustScroll ();

OnPositionChanged (_position);
}
}

/// <summary>Raised when the <see cref="Position"/> has changed.</summary>
public event EventHandler<EventArgs<int>>? PositionChanged;

/// <summary>
/// Raised when the <see cref="Position"/> is changing. Set <see cref="CancelEventArgs.Cancel"/> to
/// <see langword="true"/> to prevent the position from being changed.
/// </summary>
public event EventHandler<CancelEventArgs<int>>? PositionChanging;

/// <summary>
/// Gets or sets the size of the Scroll. This is the total size of the content that can be scrolled through.
/// </summary>
public int Size
{
get => _size;
set
{
_size = value;
OnSizeChanged (_size);
AdjustScroll ();
}
}

/// <summary>Raised when <see cref="Size"/> has changed.</summary>
public event EventHandler<EventArgs<int>>? SizeChanged;

/// <inheritdoc/>
protected internal override bool OnMouseEvent (MouseEvent mouseEvent)
{
int location = Orientation == Orientation.Vertical ? mouseEvent.Position.Y : mouseEvent.Position.X;
int barSize = Orientation == Orientation.Vertical ? GetContentSize ().Height : GetContentSize ().Width;

(int topLeft, int bottomRight) sliderPos = _orientation == Orientation.Vertical
? new (_slider.Frame.Y, _slider.Frame.Bottom - 1)
: new (_slider.Frame.X, _slider.Frame.Right - 1);

if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Pressed) && location < sliderPos.topLeft)
{
Position = Math.Max (Position - barSize, 0);
}
else if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Pressed) && location > sliderPos.bottomRight)
{
Position = Math.Min (Position + barSize, Size - barSize);
}
else if ((mouseEvent.Flags == MouseFlags.WheeledDown && Orientation == Orientation.Vertical)
|| (mouseEvent.Flags == MouseFlags.WheeledRight && Orientation == Orientation.Horizontal))
{
Position = Math.Min (Position + 1, Size - barSize);
}
else if ((mouseEvent.Flags == MouseFlags.WheeledUp && Orientation == Orientation.Vertical)
|| (mouseEvent.Flags == MouseFlags.WheeledLeft && Orientation == Orientation.Horizontal))
{
Position = Math.Max (Position - 1, 0);
}
else if (mouseEvent.Flags == MouseFlags.Button1Clicked)
{
if (_slider.Frame.Contains (mouseEvent.Position))
{
return _slider.OnMouseEvent (mouseEvent);
}
}

return base.OnMouseEvent (mouseEvent);
}

// TODO: Move this into "ScrollSlider" and override it there. Scroll can then subscribe to _slider.LayoutComplete and call AdjustSlider.
// QUESTION: I've been meaning to add a "View.FrameChanged" event (fired from LayoutComplete only if Frame has changed). Should we do that as part of this PR?
// QUESTION: Note I *did* add "View.ViewportChanged" in a previous PR.

/// <summary>Virtual method called when <see cref="Position"/> has changed. Raises <see cref="PositionChanged"/>.</summary>
protected virtual void OnPositionChanged (int position) { PositionChanged?.Invoke (this, new (in position)); }

/// <summary>
/// Virtual method called when <see cref="Position"/> is changing. Raises <see cref="PositionChanging"/>, which is
/// cancelable.
/// </summary>
protected virtual CancelEventArgs<int> OnPositionChanging (int currentPos, int newPos)
{
CancelEventArgs<int> args = new (ref currentPos, ref newPos);
PositionChanging?.Invoke (this, args);

return args;
}

/// <summary>Virtual method called when <see cref="Size"/> has changed. Raises <see cref="SizeChanged"/>.</summary>
BDisp marked this conversation as resolved.
Show resolved Hide resolved
protected void OnSizeChanged (int size) { SizeChanged?.Invoke (this, new (in size)); }

internal void AdjustScroll ()
{
if (SupView is { })
{
X = Orientation == Orientation.Vertical ? 0 : 1;
Y = Orientation == Orientation.Vertical ? 1 : 0;
Width = Orientation == Orientation.Vertical ? Dim.Fill () : Dim.Fill (1);
Height = Orientation == Orientation.Vertical ? Dim.Fill (1) : Dim.Fill ();
}

_slider.AdjustSlider ();
SetScrollText ();
}

/// <inheritdoc/>
internal override void OnLayoutComplete (LayoutEventArgs args)
tig marked this conversation as resolved.
Show resolved Hide resolved
{
base.OnLayoutComplete (args);

AdjustScroll ();
}

internal ScrollBar? SupView => SuperView as ScrollBar;

private void SetScrollText ()
{
TextDirection = Orientation == Orientation.Vertical ? TextDirection.TopBottom_LeftRight : TextDirection.LeftRight_TopBottom;

// QUESTION: Should these Glyphs be configurable via CM?
Text = string.Concat (
Enumerable.Repeat (
Glyphs.Stipple.ToString (),
GetContentSize ().Width * GetContentSize ().Height));
}
}
121 changes: 121 additions & 0 deletions Terminal.Gui/Views/Scroll/ScrollBar.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#nullable enable

using System.ComponentModel;

namespace Terminal.Gui;

/// <summary>ScrollBars are views that display a 1-character scrollbar, either horizontal or vertical</summary>
BDisp marked this conversation as resolved.
Show resolved Hide resolved
/// <remarks>
/// <para>
/// The scrollbar is drawn to be a representation of the Size, assuming that the scroll position is set at
/// Position.
/// </para>
/// <para>If the region to display the scrollbar is larger than three characters, arrow indicators are drawn.</para>
/// </remarks>
public class ScrollBar : View
{
/// <inheritdoc/>
public ScrollBar ()
{
_scroll = new ();
_decrease = new ();
_increase = new () { VariationMode = VariationMode.Increase };
Add (_scroll, _decrease, _increase);

CanFocus = false;
Orientation = Orientation.Vertical;
Width = Dim.Auto (DimAutoStyle.Content, 1);
Height = Dim.Auto (DimAutoStyle.Content, 1);

_scroll.PositionChanging += Scroll_PositionChanging;
_scroll.PositionChanged += Scroll_PositionChanged;
_scroll.SizeChanged += _scroll_SizeChanged;
}

private readonly Scroll _scroll;
BDisp marked this conversation as resolved.
Show resolved Hide resolved
private readonly ScrollButton _decrease;
private readonly ScrollButton _increase;

/// <summary>Defines if a scrollbar is vertical or horizontal.</summary>
public Orientation Orientation
{
get => _scroll.Orientation;
set
{
Resize (value);
_scroll.Orientation = value;
}
}

/// <summary>The position, relative to <see cref="Size"/>, to set the scrollbar at.</summary>
/// <value>The position.</value>
public int Position
{
get => _scroll.Position;
set
{
_scroll.Position = value;
AdjustAll ();
}
}

/// <summary>Raised when the <see cref="Position"/> has changed.</summary>
public event EventHandler<EventArgs<int>>? PositionChanged;

/// <summary>
/// Raised when the <see cref="Position"/> is changing. Set <see cref="CancelEventArgs.Cancel"/> to
/// <see langword="true"/> to prevent the position from being changed.
/// </summary>
public event EventHandler<CancelEventArgs<int>>? PositionChanging;

/// <summary>
/// Gets or sets the size of the Scroll. This is the total size of the content that can be scrolled through.
/// </summary>
public int Size
{
get => _scroll.Size;
set
{
_scroll.Size = value;
AdjustAll ();
}
}

/// <summary>Raised when <see cref="Size"/> has changed.</summary>
public event EventHandler<EventArgs<int>>? SizeChanged;

/// <inheritdoc/>
internal override void OnLayoutComplete (LayoutEventArgs args)
{
base.OnLayoutComplete (args);

AdjustAll ();
}

private void _scroll_SizeChanged (object? sender, EventArgs<int> e) { SizeChanged?.Invoke (this, e); }

private void AdjustAll ()
{
_scroll.AdjustScroll ();
_decrease.AdjustButton ();
_increase.AdjustButton ();
}

private void Resize (Orientation orientation)
{
switch (orientation)
{
case Orientation.Horizontal:

break;
case Orientation.Vertical:
break;
default:
throw new ArgumentOutOfRangeException (nameof (orientation), orientation, null);
}
}

private void Scroll_PositionChanged (object? sender, EventArgs<int> e) { PositionChanged?.Invoke (this, e); }

private void Scroll_PositionChanging (object? sender, CancelEventArgs<int> e) { PositionChanging?.Invoke (this, e); }
}
Loading
Loading