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 3 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
355 changes: 355 additions & 0 deletions Terminal.Gui/Views/Scroll.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,355 @@
//
BDisp marked this conversation as resolved.
Show resolved Hide resolved
// Scroll.cs: Vertical or horizontal scroll
//
// Author: BDisp
//
// Licensed under the MIT license
//

namespace Terminal.Gui;

/// <summary>
/// Represents the "inside part" of a scroll bar, minus the arrows.
/// </summary>
public class Scroll : View
{
/// <inheritdoc/>
public Scroll ()
{
WantContinuousButtonPressed = true;
ClearOnVisibleFalse = false;
BDisp marked this conversation as resolved.
Show resolved Hide resolved
CanFocus = false;
Orientation = Orientation.Vertical;
Width = 1;
BDisp marked this conversation as resolved.
Show resolved Hide resolved

_slider = new () { Id = "slider" };
Add (_slider);

Added += Scroll_Added;
Removed += Scroll_Removed;
Initialized += Scroll_Initialized;
DrawContent += Scroll_DrawContent;
MouseEvent += Scroll_MouseEvent;
_slider.DrawContent += Scroll_DrawContent;
_slider.MouseEvent += Slider_MouseEvent;
}

private readonly View _slider;
private int _lastLocation = -1;
tig marked this conversation as resolved.
Show resolved Hide resolved

private Orientation _orientation;
private int _size;
private int _position;

private bool _wasSliderMouse;
tig marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Determines the Orientation of the scroll.
/// </summary>
public Orientation Orientation
{
get => _orientation;
set
{
_orientation = value;
SetWidthHeight ();
}
}

/// <summary>
/// The position, relative to <see cref="Size"/>, to set the scrollbar at.
/// </summary>
public int Position
{
get => _position;
set
{
int barSize = Orientation == Orientation.Vertical ? Frame.Height : Frame.Width;

if (value < 0 || (value > 0 && value + barSize > Size))
{
return;
}

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

if (args.Cancel)
{
return;
}

int oldPos = _position;
_position = value;
OnPositionChanged (oldPos);

if (!_wasSliderMouse)
{
SetWidthHeight ();
}
}
}

/// <summary>This event is raised when the position on the scrollbar has changed.</summary>
public event EventHandler<StateEventArgs<int>> PositionChanged;

/// <summary>This event is raised when the position on the scrollbar is changing.</summary>
public event EventHandler<StateEventArgs<int>> PositionChanging;

/// <summary>
/// The size of content the scroll represents.
/// </summary>
public int Size
{
get => _size;
set
{
int oldSize = _size;
_size = value;
OnSizeChanged (oldSize);
SetWidthHeight ();
}
}

/// <summary>This event is raised when the size of the scroll has changed.</summary>
public event EventHandler<StateEventArgs<int>> SizeChanged;

/// <inheritdoc/>
protected override void Dispose (bool disposing)
{
Added -= Scroll_Added;
Initialized -= Scroll_Initialized;
DrawContent -= Scroll_DrawContent;
MouseEvent -= Scroll_MouseEvent;
_slider.DrawContent -= Scroll_DrawContent;
_slider.MouseEvent -= Slider_MouseEvent;

base.Dispose (disposing);
}

/// <summary>Virtual method to invoke the <see cref="PositionChanged"/> event handler.</summary>
protected virtual void OnPositionChanged (int oldPos) { PositionChanged?.Invoke (this, new (oldPos, Position)); }

/// <summary>Virtual method to invoke the cancelable <see cref="PositionChanging"/> event handler.</summary>
protected virtual StateEventArgs<int> OnPositionChanging (int oldPos, int newPos)
{
StateEventArgs<int> args = new (oldPos, newPos);
PositionChanging?.Invoke (this, args);

return args;
}

/// <summary>Virtual method to invoke the <see cref="SizeChanged"/> event handler.</summary>
protected void OnSizeChanged (int oldSize) { SizeChanged?.Invoke (this, new (oldSize, Size)); }

private int GetPositionFromSliderLocation (int location)
{
if (Frame.Height == 0 || Frame.Width == 0)
{
return 0;
}

int barSize = Orientation == Orientation.Vertical ? Frame.Height : Frame.Width;

return Math.Min (location * Size / barSize, Size - barSize);
}

private (int Location, int Dimension) GetSliderLocationDimensionFromPosition ()
{
if (Frame.Height == 0 || Frame.Width == 0)
{
return new (0, 0);
}

int barSize = Orientation == Orientation.Vertical ? Frame.Height : Frame.Width;
int location;
int dimension;

if (Size > 0)
{
dimension = Math.Min (Math.Max (barSize * barSize / Size, 1), barSize);

// Ensure the Position is valid
if (Position > 0 && Position + barSize > Size)
{
Position = Size - barSize;
}

location = Math.Min (Position * barSize / Size, barSize - dimension);

if (Position == Size - barSize && location + dimension < barSize)
{
location = barSize - dimension;
}
}
else
{
location = 0;
dimension = barSize;
}

return new (location, dimension);
}

private void Parent_LayoutComplete (object sender, LayoutEventArgs e)
{
if (!_wasSliderMouse)
{
SetWidthHeight ();
}
else
{
_wasSliderMouse = false;
}
}

private void Parent_MouseEnter (object sender, MouseEventEventArgs e) { OnMouseEnter (e.MouseEvent); }

private void Parent_MouseLeave (object sender, MouseEventEventArgs e) { OnMouseLeave (e.MouseEvent); }

private void Scroll_Added (object sender, SuperViewChangedEventArgs e)
{
View parent = e.Parent is Adornment adornment ? adornment.Parent : e.Parent;

parent.LayoutComplete += Parent_LayoutComplete;
parent.MouseEnter += Parent_MouseEnter;
parent.MouseLeave += Parent_MouseLeave;
}

private void Scroll_DrawContent (object sender, DrawEventArgs e) { SetColorSchemeWithSuperview (sender as View); }

private void Scroll_Initialized (object sender, EventArgs e) { SetWidthHeight (); }

private void Scroll_MouseEvent (object sender, MouseEventEventArgs e)
{
MouseEvent me = e.MouseEvent;
int location = Orientation == Orientation.Vertical ? me.Position.Y : me.Position.X;
int barSize = Orientation == Orientation.Vertical ? Frame.Height : Frame.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 (me.Flags == MouseFlags.Button1Pressed && location < sliderPos.topLeft)
{
Position = Math.Max (Position - barSize, 0);
}
else if (me.Flags == MouseFlags.Button1Pressed && location > sliderPos.bottomRight)
{
Position = Math.Min (Position + barSize, Size - barSize);
}
}

private void Scroll_Removed (object sender, SuperViewChangedEventArgs e)
{
if (e.Parent is { })
{
View parent = e.Parent is Adornment adornment ? adornment.Parent : e.Parent;

parent.LayoutComplete -= Parent_LayoutComplete;
parent.MouseEnter -= Parent_MouseEnter;
parent.MouseLeave -= Parent_MouseLeave;
}
}

private static void SetColorSchemeWithSuperview (View view)
{
if (view.SuperView is { })
{
View parent = view.SuperView is Adornment adornment ? adornment.Parent : view.SuperView;

if (view.Id == "slider")
{
view.ColorScheme = new () { Normal = new (parent.ColorScheme.Normal.Foreground, parent.ColorScheme.Normal.Foreground) };
}
else
{
view.ColorScheme = parent.ColorScheme;
}
}
}

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

Text = string.Concat (
Enumerable.Repeat (
Glyphs.Stipple.ToString (),
Frame.Width * Frame.Height));
_slider.TextDirection = Orientation == Orientation.Vertical ? TextDirection.TopBottom_LeftRight : TextDirection.LeftRight_TopBottom;

_slider.Text = string.Concat (
Enumerable.Repeat (
Glyphs.ContinuousMeterSegment.ToString (),
_slider.Frame.Width * _slider.Frame.Height));
}

private void SetWidthHeight ()
{
if (!IsInitialized)
{
return;
}

(int Location, int Dimension) slider = GetSliderLocationDimensionFromPosition ();
_slider.X = Orientation == Orientation.Vertical ? 0 : slider.Location;
_slider.Y = Orientation == Orientation.Vertical ? slider.Location : 0;
_slider.Width = Orientation == Orientation.Vertical ? Dim.Fill () : slider.Dimension;
_slider.Height = Orientation == Orientation.Vertical ? slider.Dimension : Dim.Fill ();

SetSliderText ();
}

private void Slider_MouseEvent (object sender, MouseEventEventArgs e)
{
MouseEvent me = e.MouseEvent;
int location = Orientation == Orientation.Vertical ? me.Position.Y : me.Position.X;
int barSize = Orientation == Orientation.Vertical ? Frame.Height : Frame.Width;
int offset = _lastLocation > -1 ? location - _lastLocation : 0;

if (me.Flags == MouseFlags.Button1Pressed)
{
if (Application.MouseGrabView != sender as View)
{
Application.GrabMouse (sender as View);
_lastLocation = location;
}
}
else if (me.Flags == (MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition))
{
if (Orientation == Orientation.Vertical)
{
if (_slider.Frame.Y + offset >= 0 && _slider.Frame.Y + offset + _slider.Frame.Height <= barSize)
{
_wasSliderMouse = true;
_slider.Y = _slider.Frame.Y + offset;
Position = GetPositionFromSliderLocation (_slider.Frame.Y);
}
}
else
{
if (_slider.Frame.X + offset >= 0 && _slider.Frame.X + offset + _slider.Frame.Width <= barSize)
{
_wasSliderMouse = true;
_slider.X = _slider.Frame.X + offset;
Position = GetPositionFromSliderLocation (_slider.Frame.X);
}
}
}
else if (me.Flags == MouseFlags.Button1Released)
{
_lastLocation = -1;

if (Application.MouseGrabView == sender as View)
{
Application.UngrabMouse ();
}
}
else
{
return;
}

e.Handled = true;
}
}
Loading
Loading