diff --git a/Terminal.Gui/View/View.ScrollBars.cs b/Terminal.Gui/View/View.ScrollBars.cs
index d3e56344f..d2a4845ef 100644
--- a/Terminal.Gui/View/View.ScrollBars.cs
+++ b/Terminal.Gui/View/View.ScrollBars.cs
@@ -130,11 +130,13 @@ public partial class View
{
if (_verticalScrollBar.IsValueCreated)
{
+ _verticalScrollBar.Value.ViewportDimension = Viewport.Height;
_verticalScrollBar.Value.ContentPosition = Viewport.Y;
}
if (_horizontalScrollBar.IsValueCreated)
{
+ _horizontalScrollBar.Value.ViewportDimension = Viewport.Width;
_horizontalScrollBar.Value.ContentPosition = Viewport.X;
}
};
diff --git a/Terminal.Gui/Views/Scroll/Scroll.cs b/Terminal.Gui/Views/Scroll/Scroll.cs
index 3e5bef959..39bc896c6 100644
--- a/Terminal.Gui/Views/Scroll/Scroll.cs
+++ b/Terminal.Gui/Views/Scroll/Scroll.cs
@@ -24,8 +24,9 @@ public class Scroll : View, IOrientation, IDesignable
public Scroll ()
{
_slider = new ();
- Add (_slider);
- _slider.FrameChanged += OnSliderOnFrameChanged;
+ base.Add (_slider);
+ _slider.Scroll += SliderOnScroll;
+ _slider.PositionChanged += SliderOnPositionChanged;
CanFocus = false;
@@ -38,6 +39,7 @@ public class Scroll : View, IOrientation, IDesignable
OnOrientationChanged (Orientation);
}
+
///
protected override void OnSubviewLayout (LayoutEventArgs args)
{
@@ -104,12 +106,32 @@ public class Scroll : View, IOrientation, IDesignable
set => _slider.ShowPercent = value;
}
- private int ViewportDimension => Orientation == Orientation.Vertical ? Viewport.Height : Viewport.Width;
+ private int? _viewportDimension;
+
+ ///
+ /// Gets or sets the size of the viewport into the content being scrolled, bounded by .
+ ///
+ ///
+ /// If not explicitly set, will be the appropriate dimension of the Scroll's Frame.
+ ///
+ public int ViewportDimension
+ {
+ get
+ {
+ if (_viewportDimension.HasValue)
+ {
+ return _viewportDimension.Value;
+ }
+ return Orientation == Orientation.Vertical ? Frame.Height : Frame.Width;
+
+ }
+ set => _viewportDimension = value;
+ }
private int _size;
///
- /// Gets or sets the total size of the content that can be scrolled.
+ /// Gets or sets the size of the content that can be scrolled.
///
public int Size
{
@@ -135,43 +157,37 @@ public class Scroll : View, IOrientation, IDesignable
public event EventHandler>? SizeChanged;
#region SliderPosition
- private void OnSliderOnFrameChanged (object? sender, EventArgs args)
+
+ private void SliderOnPositionChanged (object? sender, EventArgs e)
{
if (ViewportDimension == 0)
{
return;
}
- int framePos = Orientation == Orientation.Vertical ? args.CurrentValue.Y : args.CurrentValue.X;
+ int calculatedSliderPos = CalculateSliderPosition (_contentPosition);
- RaiseSliderPositionChangeEvents (CalculateSliderPosition (_contentPosition), framePos);
+ ContentPosition = (int)Math.Round ((double)e.CurrentValue / (ViewportDimension - _slider.Size) * (Size - ViewportDimension));
+
+ RaiseSliderPositionChangeEvents (calculatedSliderPos, e.CurrentValue);
+ }
+
+ private void SliderOnScroll (object? sender, EventArgs e)
+ {
+ if (ViewportDimension == 0)
+ {
+ return;
+ }
}
///
/// Gets or sets the position of the start of the Scroll slider, within the Viewport.
///
- public int SliderPosition
+ public int GetSliderPosition () => CalculateSliderPosition (_contentPosition);
+
+ private void RaiseSliderPositionChangeEvents (int calculatedSliderPosition, int newSliderPosition)
{
- get => CalculateSliderPosition (_contentPosition);
- set => RaiseSliderPositionChangeEvents (_slider.Position, value);
- }
-
- private void RaiseSliderPositionChangeEvents (int currentSliderPosition, int newSliderPosition)
- {
- if (/*newSliderPosition > Size - ViewportDimension ||*/ currentSliderPosition == newSliderPosition)
- {
- return;
- }
-
- if (OnSliderPositionChanging (currentSliderPosition, newSliderPosition))
- {
- return;
- }
-
- CancelEventArgs args = new (ref currentSliderPosition, ref newSliderPosition);
- SliderPositionChanging?.Invoke (this, args);
-
- if (args.Cancel)
+ if (/*newSliderPosition > Size - ViewportDimension ||*/ calculatedSliderPosition == newSliderPosition)
{
return;
}
@@ -179,27 +195,14 @@ public class Scroll : View, IOrientation, IDesignable
// This sets the slider position and clamps the value
_slider.Position = newSliderPosition;
- ContentPosition = (int)Math.Round ((double)newSliderPosition / (ViewportDimension - _slider.Size) * (Size - ViewportDimension));
-
OnSliderPositionChanged (newSliderPosition);
SliderPositionChanged?.Invoke (this, new (in newSliderPosition));
}
- ///
- /// Called when is changing. Return true to cancel the change.
- ///
- protected virtual bool OnSliderPositionChanging (int currentSliderPosition, int newSliderPosition) { return false; }
-
- ///
- /// Raised when the is changing. Set to
- /// to prevent the position from being changed.
- ///
- public event EventHandler>? SliderPositionChanging;
-
- /// Called when has changed.
+ /// Called when the slider position has changed.
protected virtual void OnSliderPositionChanged (int position) { }
- /// Raised when the has changed.
+ /// Raised when the slider position has changed.
public event EventHandler>? SliderPositionChanged;
private int CalculateSliderPosition (int contentPosition)
@@ -219,8 +222,17 @@ public class Scroll : View, IOrientation, IDesignable
private int _contentPosition;
///
- /// Gets or sets the position of the ScrollSlider within the range of 0....
+ /// Gets or sets the position of the slider relative to .
///
+ ///
+ ///
+ /// The content position is clamped to 0 and minus .
+ ///
+ ///
+ /// Setting will result in the and
+ /// events being raised.
+ ///
+ ///
public int ContentPosition
{
get => _contentPosition;
@@ -231,14 +243,17 @@ public class Scroll : View, IOrientation, IDesignable
return;
}
- RaiseContentPositionChangeEvents (value);
+ // Clamp the value between 0 and Size - ViewportDimension
+ int newContentPosition = (int)Math.Clamp (value, 0, Math.Max (0, Size - ViewportDimension));
+
+ RaiseContentPositionChangeEvents (newContentPosition);
+
+ _slider.SetPosition (CalculateSliderPosition (_contentPosition));
}
}
private void RaiseContentPositionChangeEvents (int newContentPosition)
{
- // Clamp the value between 0 and Size - ViewportDimension
- newContentPosition = (int)Math.Clamp (newContentPosition, 0, Math.Max (0, Size - ViewportDimension));
if (OnContentPositionChanging (_contentPosition, newContentPosition))
{
@@ -255,8 +270,6 @@ public class Scroll : View, IOrientation, IDesignable
_contentPosition = newContentPosition;
- SliderPosition = CalculateSliderPosition (_contentPosition);
-
OnContentPositionChanged (_contentPosition);
ContentPositionChanged?.Invoke (this, new (in _contentPosition));
}
@@ -291,35 +304,39 @@ public class Scroll : View, IOrientation, IDesignable
///
protected override bool OnMouseClick (MouseEventArgs args)
{
+ // Check if the mouse click is a single click
if (!args.IsSingleClicked)
{
return false;
}
+ int sliderCenter;
+ int distanceFromCenter;
+
if (Orientation == Orientation.Vertical)
{
- // If the position is w/in the slider frame ignore
- if (args.Position.Y >= _slider.Frame.Y && args.Position.Y < _slider.Frame.Y + _slider.Frame.Height)
- {
- return false;
- }
-
- SliderPosition = args.Position.Y;
+ sliderCenter = _slider.Frame.Y + _slider.Frame.Height / 2;
+ distanceFromCenter = args.Position.Y - sliderCenter;
}
else
{
- // If the position is w/in the slider frame ignore
- if (args.Position.X >= _slider.Frame.X && args.Position.X < _slider.Frame.X + _slider.Frame.Width)
- {
- return false;
- }
-
- SliderPosition = args.Position.X;
+ sliderCenter = _slider.Frame.X + _slider.Frame.Width / 2;
+ distanceFromCenter = args.Position.X - sliderCenter;
}
+ // Ratio of the distance to the viewport dimension
+ double ratio = (double)Math.Abs (distanceFromCenter) / ViewportDimension;
+ // Jump size based on the ratio and the total content size
+ int jump = (int)Math.Ceiling (ratio * Size);
+
+ // Adjust the content position based on the distance
+ ContentPosition += distanceFromCenter < 0 ? -jump : jump;
+
return true;
}
+
+
///
/// Gets or sets the amount each mouse hweel event will incremenet/decrement the .
///
diff --git a/Terminal.Gui/Views/Scroll/ScrollBar.cs b/Terminal.Gui/Views/Scroll/ScrollBar.cs
index a0a8a52c1..3cc48bea4 100644
--- a/Terminal.Gui/Views/Scroll/ScrollBar.cs
+++ b/Terminal.Gui/Views/Scroll/ScrollBar.cs
@@ -11,9 +11,6 @@ namespace Terminal.Gui;
/// and clicking with the mouse to scroll.
///
///
-///
-/// indicates the number of rows or columns the Scroll has moved from 0.
-///
///
public class ScrollBar : View, IOrientation, IDesignable
{
@@ -27,7 +24,6 @@ public class ScrollBar : View, IOrientation, IDesignable
CanFocus = false;
_scroll = new ();
- _scroll.SliderPositionChanging += OnScrollOnSliderPositionChanging;
_scroll.SliderPositionChanged += OnScrollOnSliderPositionChanged;
_scroll.ContentPositionChanging += OnScrollOnContentPositionChanging;
_scroll.ContentPositionChanged += OnScrollOnContentPositionChanged;
@@ -112,6 +108,8 @@ public class ScrollBar : View, IOrientation, IDesignable
Height = 1;
}
+ // Force a layout to ensure _scroll
+ Layout ();
_scroll.Orientation = newOrientation;
}
@@ -183,43 +181,34 @@ public class ScrollBar : View, IOrientation, IDesignable
}
/// Gets or sets the position of the slider within the ScrollBar's Viewport.
- /// The position.
- public int SliderPosition
- {
- get => _scroll.SliderPosition;
- set => _scroll.SliderPosition = value;
- }
+ /// The position.
+ public int GetSliderPosition () => _scroll.GetSliderPosition ();
- private void OnScrollOnSliderPositionChanging (object? sender, CancelEventArgs e) { SliderPositionChanging?.Invoke (this, e); }
private void OnScrollOnSliderPositionChanged (object? sender, EventArgs e) { SliderPositionChanged?.Invoke (this, e); }
- ///
- /// Raised when the is changing. Set to
- /// to prevent the position from being changed.
- ///
- public event EventHandler>? SliderPositionChanging;
-
- /// Raised when the has changed.
+ /// Raised when the position of the slider has changed.
public event EventHandler>? SliderPositionChanged;
-
///
/// Gets or sets the size of the Scroll. This is the total size of the content that can be scrolled through.
///
public int Size
{
- get
- {
- // Add two for increment/decrement buttons
- return _scroll.Size + 2;
- }
- set
- {
- // Remove two for increment/decrement buttons
- _scroll.Size = value - 2;
- }
+ get => _scroll.Size;
+ set => _scroll.Size = value;
}
+ ///
+ /// Gets or sets the size of the viewport into the content being scrolled, bounded by .
+ ///
+ ///
+ /// If not explicitly set, will be the appropriate dimension of the Scroll's Frame.
+ ///
+ public int ViewportDimension
+ {
+ get => _scroll.ViewportDimension;
+ set => _scroll.ViewportDimension = value;
+ }
///
/// Gets or sets the position of the ScrollSlider within the range of 0....
///
@@ -233,12 +222,12 @@ public class ScrollBar : View, IOrientation, IDesignable
private void OnScrollOnContentPositionChanged (object? sender, EventArgs e) { ContentPositionChanged?.Invoke (this, e); }
///
- /// Raised when the is changing. Set to
+ /// Raised when the is changing. Set to
/// to prevent the position from being changed.
///
public event EventHandler>? ContentPositionChanging;
- /// Raised when the has changed.
+ /// Raised when the has changed.
public event EventHandler>? ContentPositionChanged;
/// Raised when has changed.
@@ -320,7 +309,7 @@ public class ScrollBar : View, IOrientation, IDesignable
Width = 1;
Height = Dim.Fill ();
Size = 200;
- SliderPosition = 10;
+ ContentPosition = 10;
//ShowPercent = true;
return true;
}
diff --git a/Terminal.Gui/Views/Scroll/ScrollSlider.cs b/Terminal.Gui/Views/Scroll/ScrollSlider.cs
index a3e58bedd..c61c9bc04 100644
--- a/Terminal.Gui/Views/Scroll/ScrollSlider.cs
+++ b/Terminal.Gui/Views/Scroll/ScrollSlider.cs
@@ -1,5 +1,6 @@
#nullable enable
+using System.ComponentModel;
using System.Diagnostics;
namespace Terminal.Gui;
@@ -39,6 +40,8 @@ public class ScrollSlider : View, IOrientation, IDesignable
// Default size is 1
Size = 1;
+
+ FrameChanged += OnFrameChanged;
}
#region IOrientation members
@@ -67,6 +70,7 @@ public class ScrollSlider : View, IOrientation, IDesignable
// Reset Position to 0 when changing orientation
X = 0;
Y = 0;
+ //Position = 0;
// Reset Size to 1 when changing orientation
if (Orientation == Orientation.Vertical)
@@ -103,7 +107,7 @@ public class ScrollSlider : View, IOrientation, IDesignable
set
{
_showPercent = value;
- SetNeedsDraw();
+ SetNeedsDraw ();
}
}
@@ -123,11 +127,11 @@ public class ScrollSlider : View, IOrientation, IDesignable
{
if (Orientation == Orientation.Vertical)
{
- return Frame.Height;
+ return Viewport.Height;
}
else
{
- return Frame.Width;
+ return Viewport.Width;
}
}
set
@@ -148,38 +152,123 @@ public class ScrollSlider : View, IOrientation, IDesignable
}
///
- /// Gets or sets the position of the ScrollSlider relative to the size of the ScrollSlider's Frame. This is a helper that simply gets or sets the X or Y depending on the
- /// . The position will be constrained such that the ScrollSlider will not go outside the Viewport of
+ /// Gets the size of the viewport into the content being scrolled, bounded by .
+ ///
+ ///
+ /// This is the SuperView's Viewport demension.
+ ///
+ public int ViewportDimension => Orientation == Orientation.Vertical ? SuperView?.Viewport.Height ?? 0 : SuperView?.Viewport.Width ?? 0;
+
+ private void OnFrameChanged (object? sender, EventArgs e)
+ {
+ Position = Orientation == Orientation.Vertical ? e.CurrentValue.Y : e.CurrentValue.X;
+ }
+
+ private int _position;
+
+ ///
+ /// Gets or sets the position of the ScrollSlider relative to the size of the ScrollSlider's Frame.
+ /// The position will be constrained such that the ScrollSlider will not go outside the Viewport of
/// the .
///
public int Position
{
- get
- {
- if (Orientation == Orientation.Vertical)
- {
- return Frame.Y;
- }
- else
- {
- return Frame.X;
- }
- }
+ get => _position;
set
{
- if (Orientation == Orientation.Vertical)
+ if (_position == value)
{
- int viewport = Math.Max (1, SuperView?.Viewport.Height ?? 1);
- Y = Math.Clamp (value, 0, viewport - Frame.Height);
- }
- else
- {
- int viewport = Math.Max (1, SuperView?.Viewport.Width ?? 1);
- X = Math.Clamp (value, 0, viewport - Frame.Width);
+ return;
}
+
+ RaisePositionChangeEvents (ClampPosition (value));
+
+ SetNeedsLayout ();
}
}
+ public void SetPosition (int position)
+ {
+ _position = ClampPosition (position);
+
+ if (Orientation == Orientation.Vertical)
+ {
+ Y = _position;
+ }
+ else
+ {
+ X = _position;
+ }
+ }
+
+ private int ClampPosition (int newPosittion)
+ {
+ if (SuperView is null || !IsInitialized)
+ {
+ return 1;
+ }
+
+ if (Orientation == Orientation.Vertical)
+ {
+ return Math.Clamp (newPosittion, 0, ViewportDimension - Viewport.Height);
+ }
+ else
+ {
+ return Math.Clamp (newPosittion, 0, ViewportDimension - Viewport.Width);
+ }
+ }
+
+ private void RaisePositionChangeEvents (int newPosition)
+ {
+ if (OnPositionChanging (_position, newPosition))
+ {
+ return;
+ }
+
+ CancelEventArgs args = new (ref _position, ref newPosition);
+ PositionChanging?.Invoke (this, args);
+
+ if (args.Cancel)
+ {
+ return;
+ }
+
+ int scrollAmount = newPosition -_position;
+ _position = newPosition;
+
+ OnPositionChanged (_position);
+ PositionChanged?.Invoke (this, new (in _position));
+
+ OnScroll (scrollAmount);
+ Scroll?.Invoke (this, new (in scrollAmount));
+
+ RaiseSelecting (new CommandContext (Command.Select, null, null, scrollAmount));
+ }
+
+ ///
+ /// Called when is changing. Return true to cancel the change.
+ ///
+ protected virtual bool OnPositionChanging (int currentPos, int newPos) { return false; }
+
+ ///
+ /// Raised when the is changing. Set to
+ /// to prevent the position from being changed.
+ ///
+ public event EventHandler>? PositionChanging;
+
+ /// Called when has changed.
+ protected virtual void OnPositionChanged (int position) { }
+
+ /// Raised when the has changed.
+ public event EventHandler>? PositionChanged;
+
+
+ /// Called when has changed. Indicates how much to scroll.
+ protected virtual void OnScroll (int scrollAmount) { }
+
+ /// Raised when the has changed. Indicates how much to scroll.
+ public event EventHandler>? Scroll;
+
///
protected override bool OnDrawingText ()
{
@@ -240,7 +329,7 @@ public class ScrollSlider : View, IOrientation, IDesignable
if (Orientation == Orientation.Vertical)
{
Y = Frame.Y + offset < 0
- ? 0
+ ? 0
: Frame.Y + offset + Frame.Height > superViewDimension
? Math.Max (superViewDimension - Frame.Height, 0)
: Frame.Y + offset;
@@ -248,7 +337,7 @@ public class ScrollSlider : View, IOrientation, IDesignable
else
{
X = Frame.X + offset < 0
- ? 0
+ ? 0
: Frame.X + offset + Frame.Width > superViewDimension
? Math.Max (superViewDimension - Frame.Width, 0)
: Frame.X + offset;
diff --git a/UICatalog/Scenarios/CharacterMap.cs b/UICatalog/Scenarios/CharacterMap/CharMap.cs
similarity index 56%
rename from UICatalog/Scenarios/CharacterMap.cs
rename to UICatalog/Scenarios/CharacterMap/CharMap.cs
index 4ff95e423..fd5072fb0 100644
--- a/UICatalog/Scenarios/CharacterMap.cs
+++ b/UICatalog/Scenarios/CharacterMap/CharMap.cs
@@ -1,353 +1,38 @@
-#define OTHER_CONTROLS
-
+#nullable enable
using System;
-using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.Http;
-using System.Reflection;
using System.Text;
using System.Text.Json;
-using System.Text.Unicode;
-using System.Threading.Tasks;
using Terminal.Gui;
-using static Terminal.Gui.SpinnerStyle;
namespace UICatalog.Scenarios;
///
-/// This Scenario demonstrates building a custom control (a class deriving from View) that: - Provides a
-/// "Character Map" application (like Windows' charmap.exe). - Helps test unicode character rendering in Terminal.Gui -
-/// Illustrates how to do infinite scrolling
+/// A scrollable map of the Unicode codepoints.
///
-[ScenarioMetadata ("Character Map", "Unicode viewer demonstrating infinite content, scrolling, and Unicode.")]
-[ScenarioCategory ("Text and Formatting")]
-[ScenarioCategory ("Drawing")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("Layout")]
-[ScenarioCategory ("Scrolling")]
-public class CharacterMap : Scenario
+///
+/// See for details.
+///
+public class CharMap : View, IDesignable
{
- public Label _errorLabel;
- private TableView _categoryList;
- private CharMap _charMap;
-
- // Don't create a Window, just return the top-level view
- public override void Main ()
- {
- Application.Init ();
-
- var top = new Window
- {
- BorderStyle = LineStyle.None
- };
-
- _charMap = new ()
- {
- X = 0,
- Y = 0,
- Width = Dim.Fill (Dim.Func (() => _categoryList.Frame.Width)),
- Height = Dim.Fill ()
- };
- top.Add (_charMap);
-
-#if OTHER_CONTROLS
- _charMap.Y = 1;
-
- var jumpLabel = new Label
- {
- X = Pos.Right (_charMap) + 1,
- Y = Pos.Y (_charMap),
- HotKeySpecifier = (Rune)'_',
- Text = "_Jump To Code Point:"
- };
- top.Add (jumpLabel);
-
- var jumpEdit = new TextField
- {
- X = Pos.Right (jumpLabel) + 1, Y = Pos.Y (_charMap), Width = 10, Caption = "e.g. 01BE3"
- };
- top.Add (jumpEdit);
-
- _errorLabel = new ()
- {
- X = Pos.Right (jumpEdit) + 1, Y = Pos.Y (_charMap), ColorScheme = Colors.ColorSchemes ["error"], Text = "err"
- };
- top.Add (_errorLabel);
-
- jumpEdit.Accepting += JumpEditOnAccept;
-
- _categoryList = new () { X = Pos.Right (_charMap), Y = Pos.Bottom (jumpLabel), Height = Dim.Fill () };
- _categoryList.FullRowSelect = true;
- _categoryList.MultiSelect = false;
-
- //jumpList.Style.ShowHeaders = false;
- //jumpList.Style.ShowHorizontalHeaderOverline = false;
- //jumpList.Style.ShowHorizontalHeaderUnderline = false;
- _categoryList.Style.ShowHorizontalBottomline = true;
-
- //jumpList.Style.ShowVerticalCellLines = false;
- //jumpList.Style.ShowVerticalHeaderLines = false;
- _categoryList.Style.AlwaysShowHeaders = true;
-
- var isDescending = false;
-
- _categoryList.Table = CreateCategoryTable (0, isDescending);
-
- // if user clicks the mouse in TableView
- _categoryList.MouseClick += (s, e) =>
- {
- _categoryList.ScreenToCell (e.Position, out int? clickedCol);
-
- if (clickedCol != null && e.Flags.HasFlag (MouseFlags.Button1Clicked))
- {
- EnumerableTableSource table = (EnumerableTableSource)_categoryList.Table;
- string prevSelection = table.Data.ElementAt (_categoryList.SelectedRow).Category;
- isDescending = !isDescending;
-
- _categoryList.Table = CreateCategoryTable (clickedCol.Value, isDescending);
-
- table = (EnumerableTableSource)_categoryList.Table;
-
- _categoryList.SelectedRow = table.Data
- .Select ((item, index) => new { item, index })
- .FirstOrDefault (x => x.item.Category == prevSelection)
- ?.index
- ?? -1;
- }
- };
-
- int longestName = UnicodeRange.Ranges.Max (r => r.Category.GetColumns ());
-
- _categoryList.Style.ColumnStyles.Add (
- 0,
- new () { MaxWidth = longestName, MinWidth = longestName, MinAcceptableWidth = longestName }
- );
- _categoryList.Style.ColumnStyles.Add (1, new () { MaxWidth = 1, MinWidth = 6 });
- _categoryList.Style.ColumnStyles.Add (2, new () { MaxWidth = 1, MinWidth = 6 });
-
- _categoryList.Width = _categoryList.Style.ColumnStyles.Sum (c => c.Value.MinWidth) + 4;
-
- _categoryList.SelectedCellChanged += (s, args) =>
- {
- EnumerableTableSource table = (EnumerableTableSource)_categoryList.Table;
- _charMap.StartCodePoint = table.Data.ToArray () [args.NewRow].Start;
- };
-
- top.Add (_categoryList);
-
- var menu = new MenuBar
- {
- Menus =
- [
- new (
- "_File",
- new MenuItem []
- {
- new (
- "_Quit",
- $"{Application.QuitKey}",
- () => Application.RequestStop ()
- )
- }
- ),
- new (
- "_Options",
- new [] { CreateMenuShowWidth () }
- )
- ]
- };
- top.Add (menu);
-#endif // OTHER_CONTROLS
-
- _charMap.SelectedCodePoint = 0;
- _charMap.SetFocus ();
-
- Application.Run (top);
- top.Dispose ();
- Application.Shutdown ();
-
- return;
-
- void JumpEditOnAccept (object sender, CommandEventArgs e)
- {
- if (jumpEdit.Text.Length == 0)
- {
- return;
- }
-
- uint result = 0;
-
- if (jumpEdit.Text.StartsWith ("U+", StringComparison.OrdinalIgnoreCase) || jumpEdit.Text.StartsWith ("\\u"))
- {
- try
- {
- result = uint.Parse (jumpEdit.Text [2..], NumberStyles.HexNumber);
- }
- catch (FormatException)
- {
- _errorLabel.Text = "Invalid hex value";
-
- return;
- }
- }
- else if (jumpEdit.Text.StartsWith ("0", StringComparison.OrdinalIgnoreCase) || jumpEdit.Text.StartsWith ("\\u"))
- {
- try
- {
- result = uint.Parse (jumpEdit.Text, NumberStyles.HexNumber);
- }
- catch (FormatException)
- {
- _errorLabel.Text = "Invalid hex value";
-
- return;
- }
- }
- else
- {
- try
- {
- result = uint.Parse (jumpEdit.Text, NumberStyles.Integer);
- }
- catch (FormatException)
- {
- _errorLabel.Text = "Invalid value";
-
- return;
- }
- }
-
- if (result > RuneExtensions.MaxUnicodeCodePoint)
- {
- _errorLabel.Text = "Beyond maximum codepoint";
-
- return;
- }
-
- _errorLabel.Text = $"U+{result:x5}";
-
- EnumerableTableSource table = (EnumerableTableSource)_categoryList.Table;
-
- _categoryList.SelectedRow = table.Data
- .Select ((item, index) => new { item, index })
- .FirstOrDefault (x => x.item.Start <= result && x.item.End >= result)
- ?.index
- ?? -1;
- _categoryList.EnsureSelectedCellIsVisible ();
-
- // Ensure the typed glyph is selected
- _charMap.SelectedCodePoint = (int)result;
-
- // Cancel the event to prevent ENTER from being handled elsewhere
- e.Cancel = true;
- }
- }
-
- private EnumerableTableSource CreateCategoryTable (int sortByColumn, bool descending)
- {
- Func orderBy;
- var categorySort = string.Empty;
- var startSort = string.Empty;
- var endSort = string.Empty;
-
- string sortIndicator = descending ? CM.Glyphs.DownArrow.ToString () : CM.Glyphs.UpArrow.ToString ();
-
- switch (sortByColumn)
- {
- case 0:
- orderBy = r => r.Category;
- categorySort = sortIndicator;
-
- break;
- case 1:
- orderBy = r => r.Start;
- startSort = sortIndicator;
-
- break;
- case 2:
- orderBy = r => r.End;
- endSort = sortIndicator;
-
- break;
- default:
- throw new ArgumentException ("Invalid column number.");
- }
-
- IOrderedEnumerable sortedRanges = descending
- ? UnicodeRange.Ranges.OrderByDescending (orderBy)
- : UnicodeRange.Ranges.OrderBy (orderBy);
-
- return new (
- sortedRanges,
- new ()
- {
- { $"Category{categorySort}", s => s.Category },
- { $"Start{startSort}", s => $"{s.Start:x5}" },
- { $"End{endSort}", s => $"{s.End:x5}" }
- }
- );
- }
-
- private MenuItem CreateMenuShowWidth ()
- {
- var item = new MenuItem { Title = "_Show Glyph Width" };
- item.CheckType |= MenuItemCheckStyle.Checked;
- item.Checked = _charMap?.ShowGlyphWidths;
- item.Action += () => { _charMap.ShowGlyphWidths = (bool)(item.Checked = !item.Checked); };
-
- return item;
- }
-
- public override List GetDemoKeyStrokes ()
- {
- List keys = new ();
-
- for (var i = 0; i < 200; i++)
- {
- keys.Add (Key.CursorDown);
- }
-
- // Category table
- keys.Add (Key.Tab.WithShift);
-
- // Block elements
- keys.Add (Key.B);
- keys.Add (Key.L);
-
- keys.Add (Key.Tab);
-
- for (var i = 0; i < 200; i++)
- {
- keys.Add (Key.CursorLeft);
- }
-
- return keys;
- }
-}
-
-internal class CharMap : View, IDesignable
-{
- private const int COLUMN_WIDTH = 3;
+ private const int COLUMN_WIDTH = 3; // Width of each column of glyphs
+ private int _rowHeight = 1; // Height of each row of 16 glyphs - changing this is not tested
private ContextMenu _contextMenu = new ();
- private int _rowHeight = 1;
- private int _selected;
- private int _start;
-
private readonly ScrollBar _vScrollBar;
private readonly ScrollBar _hScrollBar;
+ ///
+ /// Initalizes a new instance.
+ ///
public CharMap ()
{
- ColorScheme = Colors.ColorSchemes ["Dialog"];
+ base.ColorScheme = Colors.ColorSchemes ["Dialog"];
CanFocus = true;
CursorVisibility = CursorVisibility.Default;
- //ViewportSettings = ViewportSettings.AllowLocationGreaterThanContentSize;
-
- SetContentSize (new (COLUMN_WIDTH * 16 + RowLabelWidth, _maxCodePoint / 16 * _rowHeight + 1)); // +1 for Header
-
AddCommand (
Command.Up,
() =>
@@ -424,7 +109,7 @@ internal class CharMap : View, IDesignable
Command.End,
() =>
{
- SelectedCodePoint = _maxCodePoint;
+ SelectedCodePoint = MAX_CODE_POINT;
return true;
}
@@ -453,7 +138,9 @@ internal class CharMap : View, IDesignable
MouseEvent += Handle_MouseEvent;
// Add scrollbars
- Padding.Thickness = new (0, 0, 1, 0);
+ Padding!.Thickness = new (0, 0, 1, 0);
+
+ SetContentSize (new (COLUMN_WIDTH * 16 + RowLabelWidth, MAX_CODE_POINT / 16 * _rowHeight + 1)); // +1 for Header
_hScrollBar = new ()
{
@@ -463,7 +150,7 @@ internal class CharMap : View, IDesignable
Orientation = Orientation.Horizontal,
Width = Dim.Fill (1),
Size = GetContentSize ().Width - RowLabelWidth,
- Increment = COLUMN_WIDTH
+ Increment = COLUMN_WIDTH,
};
_vScrollBar = new ()
@@ -510,48 +197,45 @@ internal class CharMap : View, IDesignable
Padding.Thickness = Padding.Thickness with { Bottom = 0 };
}
- _hScrollBar.ContentPosition = Viewport.X;
- _vScrollBar.ContentPosition = Viewport.Y;
+ //_hScrollBar.ContentPosition = Viewport.X;
+ //_vScrollBar.ContentPosition = Viewport.Y;
};
+
+ SubviewsLaidOut += (sender, args) =>
+ {
+ //_vScrollBar.ContentPosition = Viewport.Y;
+ //_hScrollBar.ContentPosition = Viewport.X;
+ };
}
- private void Handle_MouseEvent (object sender, MouseEventArgs e)
+ private void ScrollToMakeCursorVisible (Point newCursor)
{
- if (e.Flags == MouseFlags.WheeledDown)
+ // Adjust vertical scrolling
+ if (newCursor.Y < 1) // Header is at Y = 0
{
- ScrollVertical (1);
- _vScrollBar.ContentPosition = Viewport.Y;
- e.Handled = true;
-
- return;
+ ScrollVertical (newCursor.Y - 1);
+ }
+ else if (newCursor.Y >= Viewport.Height)
+ {
+ ScrollVertical (newCursor.Y - Viewport.Height + 1);
}
- if (e.Flags == MouseFlags.WheeledUp)
+ // Adjust horizontal scrolling
+ if (newCursor.X < RowLabelWidth + 1)
{
- ScrollVertical (-1);
- _vScrollBar.ContentPosition = Viewport.Y;
- e.Handled = true;
-
- return;
+ ScrollHorizontal (newCursor.X - (RowLabelWidth + 1));
+ }
+ else if (newCursor.X >= Viewport.Width)
+ {
+ ScrollHorizontal (newCursor.X - Viewport.Width + 1);
}
- if (e.Flags == MouseFlags.WheeledRight)
- {
- ScrollHorizontal (1);
- _hScrollBar.ContentPosition = Viewport.X;
- e.Handled = true;
-
- return;
- }
-
- if (e.Flags == MouseFlags.WheeledLeft)
- {
- ScrollHorizontal (-1);
- _hScrollBar.ContentPosition = Viewport.X;
- e.Handled = true;
- }
+ _vScrollBar.ContentPosition = Viewport.Y;
+ _hScrollBar.ContentPosition = Viewport.X;
}
+ #region Cursor
+
/// Gets or sets the coordinates of the Cursor based on the SelectedCodePoint in Viewport-relative coordinates
public Point Cursor
{
@@ -565,7 +249,30 @@ internal class CharMap : View, IDesignable
set => throw new NotImplementedException ();
}
- public static int _maxCodePoint = UnicodeRange.Ranges.Max (r => r.End);
+ public override Point? PositionCursor ()
+ {
+ if (HasFocus
+ && Cursor.X >= RowLabelWidth
+ && Cursor.X < Viewport.Width
+ && Cursor.Y > 0
+ && Cursor.Y < Viewport.Height)
+ {
+ Move (Cursor.X, Cursor.Y);
+ }
+ else
+ {
+ return null;
+ }
+
+ return Cursor;
+ }
+
+ #endregion Cursor
+
+ // ReSharper disable once InconsistentNaming
+ private static readonly int MAX_CODE_POINT = UnicodeRange.Ranges.Max (r => r.End);
+ private int _selectedCodepoint; // Currently selected codepoint
+ private int _startCodepoint; // The codepoint that will be displayed at the top of the Viewport
///
/// Gets or sets the currently selected codepoint. Causes the Viewport to scroll to make the selected code point
@@ -573,16 +280,15 @@ internal class CharMap : View, IDesignable
///
public int SelectedCodePoint
{
- get => _selected;
+ get => _selectedCodepoint;
set
{
- if (_selected == value)
+ if (_selectedCodepoint == value)
{
return;
}
- Point prevCursor = Cursor;
- int newSelectedCodePoint = Math.Clamp (value, 0, _maxCodePoint);
+ int newSelectedCodePoint = Math.Clamp (value, 0, MAX_CODE_POINT);
Point newCursor = new ()
{
@@ -590,42 +296,38 @@ internal class CharMap : View, IDesignable
Y = newSelectedCodePoint / 16 * _rowHeight + 1 - Viewport.Y
};
+ _selectedCodepoint = newSelectedCodePoint;
+
// Ensure the new cursor position is visible
- EnsureCursorIsVisible (newCursor);
+ ScrollToMakeCursorVisible (newCursor);
- _selected = newSelectedCodePoint;
SetNeedsDraw ();
- SelectedCodePointChanged?.Invoke (this, new (SelectedCodePoint, null));
+ SelectedCodePointChanged?.Invoke (this, new (SelectedCodePoint));
}
}
- private void EnsureCursorIsVisible (Point newCursor)
+ ///
+ /// Raised when the selected code point changes.
+ ///
+ public event EventHandler>? SelectedCodePointChanged;
+
+ ///
+ /// Specifies the starting offset for the character map. The default is 0x2500 which is the Box Drawing
+ /// characters.
+ ///
+ public int StartCodePoint
{
- // Adjust vertical scrolling
- if (newCursor.Y < 1) // Header is at Y = 0
+ get => _startCodepoint;
+ set
{
- ScrollVertical (newCursor.Y - 1);
+ _startCodepoint = value;
+ SelectedCodePoint = value;
}
- else if (newCursor.Y >= Viewport.Height)
- {
- ScrollVertical (newCursor.Y - Viewport.Height + 1);
- }
-
- _vScrollBar.ContentPosition = Viewport.Y;
-
- // Adjust horizontal scrolling
- if (newCursor.X < RowLabelWidth + 1)
- {
- ScrollHorizontal (newCursor.X - (RowLabelWidth + 1));
- }
- else if (newCursor.X >= Viewport.Width)
- {
- ScrollHorizontal (newCursor.X - Viewport.Width + 1);
- }
-
- _hScrollBar.ContentPosition = Viewport.X;
}
+ ///
+ /// Gets or sets whether the number of columns each glyph is displayed.
+ ///
public bool ShowGlyphWidths
{
get => _rowHeight == 2;
@@ -636,25 +338,12 @@ internal class CharMap : View, IDesignable
}
}
- ///
- /// Specifies the starting offset for the character map. The default is 0x2500 which is the Box Drawing
- /// characters.
- ///
- public int StartCodePoint
- {
- get => _start;
- set
- {
- _start = value;
- SelectedCodePoint = value;
- Viewport = Viewport with { Y = SelectedCodePoint / 16 * _rowHeight };
- SetNeedsDraw ();
- }
- }
+ private void CopyCodePoint () { Clipboard.Contents = $"U+{SelectedCodePoint:x5}"; }
+ private void CopyGlyph () { Clipboard.Contents = $"{new Rune (SelectedCodePoint)}"; }
- private static int RowLabelWidth => $"U+{_maxCodePoint:x5}".Length + 1;
- private static int RowWidth => RowLabelWidth + COLUMN_WIDTH * 16;
- public event EventHandler Hover;
+ #region Drawing
+
+ private static int RowLabelWidth => $"U+{MAX_CODE_POINT:x5}".Length + 1;
protected override bool OnDrawingContent ()
{
@@ -682,7 +371,7 @@ internal class CharMap : View, IDesignable
Move (x, 0);
SetAttribute (GetHotNormalColor ());
AddStr (" ");
- SetAttribute (HasFocus && cursorCol + firstColumnX == x ? ColorScheme.HotFocus : GetHotNormalColor ());
+ SetAttribute (HasFocus && cursorCol + firstColumnX == x ? GetHotFocusColor () : GetHotNormalColor ());
AddStr ($"{hexDigit:x}");
SetAttribute (GetHotNormalColor ());
AddStr (" ");
@@ -697,7 +386,7 @@ internal class CharMap : View, IDesignable
int val = row * 16;
- if (val > _maxCodePoint)
+ if (val > MAX_CODE_POINT)
{
break;
}
@@ -770,7 +459,7 @@ internal class CharMap : View, IDesignable
else
{
// Draw the width of the rune
- SetAttribute (ColorScheme.HotNormal);
+ SetAttribute (GetHotNormalColor ());
AddStr ($"{width}");
}
@@ -784,7 +473,7 @@ internal class CharMap : View, IDesignable
// Draw row label (U+XXXX_)
Move (0, y);
- SetAttribute (HasFocus && y + Viewport.Y - 1 == cursorRow ? ColorScheme.HotFocus : ColorScheme.HotNormal);
+ SetAttribute (HasFocus && y + Viewport.Y - 1 == cursorRow ? GetHotFocusColor () : GetHotNormalColor ());
if (!ShowGlyphWidths || (y + Viewport.Y) % _rowHeight > 0)
{
@@ -799,26 +488,11 @@ internal class CharMap : View, IDesignable
return true;
}
- public override Point? PositionCursor ()
- {
- if (HasFocus
- && Cursor.X >= RowLabelWidth
- && Cursor.X < Viewport.Width
- && Cursor.Y > 0
- && Cursor.Y < Viewport.Height)
- {
- Move (Cursor.X, Cursor.Y);
- }
- else
- {
- return null;
- }
-
- return Cursor;
- }
-
- public event EventHandler SelectedCodePointChanged;
-
+ ///
+ /// Helper to convert a string into camel case.
+ ///
+ ///
+ ///
public static string ToCamelCase (string str)
{
if (string.IsNullOrEmpty (str))
@@ -834,10 +508,51 @@ internal class CharMap : View, IDesignable
return str;
}
- private void CopyCodePoint () { Clipboard.Contents = $"U+{SelectedCodePoint:x5}"; }
- private void CopyGlyph () { Clipboard.Contents = $"{new Rune (SelectedCodePoint)}"; }
+ #endregion Drawing
- private void Handle_MouseClick (object sender, MouseEventArgs me)
+ #region Mouse Handling
+
+ // TODO: Use this to demonstrate using a popover to show glyph info on hover
+ public event EventHandler? Hover;
+
+ private void Handle_MouseEvent (object? sender, MouseEventArgs e)
+ {
+ if (e.Flags == MouseFlags.WheeledDown)
+ {
+ ScrollVertical (1);
+ _vScrollBar.ContentPosition = Viewport.Y;
+ e.Handled = true;
+
+ return;
+ }
+
+ if (e.Flags == MouseFlags.WheeledUp)
+ {
+ ScrollVertical (-1);
+ _vScrollBar.ContentPosition = Viewport.Y;
+ e.Handled = true;
+
+ return;
+ }
+
+ if (e.Flags == MouseFlags.WheeledRight)
+ {
+ ScrollHorizontal (1);
+ _hScrollBar.ContentPosition = Viewport.X;
+ e.Handled = true;
+
+ return;
+ }
+
+ if (e.Flags == MouseFlags.WheeledLeft)
+ {
+ ScrollHorizontal (-1);
+ _hScrollBar.ContentPosition = Viewport.X;
+ e.Handled = true;
+ }
+ }
+
+ private void Handle_MouseClick (object? sender, MouseEventArgs me)
{
if (me.Flags != MouseFlags.ReportMousePosition && me.Flags != MouseFlags.Button1Clicked && me.Flags != MouseFlags.Button1DoubleClicked)
{
@@ -864,7 +579,7 @@ internal class CharMap : View, IDesignable
int val = row * 16 + col;
- if (val > _maxCodePoint)
+ if (val > MAX_CODE_POINT)
{
return;
}
@@ -931,32 +646,41 @@ internal class CharMap : View, IDesignable
}
}
+ #endregion Mouse Handling
+
+ #region Details Dialog
+
private void ShowDetails ()
{
- var client = new UcdApiClient ();
+ UcdApiClient? client = new ();
var decResponse = string.Empty;
var getCodePointError = string.Empty;
- var waitIndicator = new Dialog
+ Dialog? waitIndicator = new ()
{
Title = "Getting Code Point Information",
X = Pos.Center (),
Y = Pos.Center (),
- Height = 7,
- Width = 50,
- Buttons = [new () { Text = "Cancel" }]
+ Width = 40,
+ Height = 10,
+ Buttons = [new () { Text = "_Cancel" }]
};
var errorLabel = new Label
{
Text = UcdApiClient.BaseUrl,
X = 0,
- Y = 1,
+ Y = 0,
Width = Dim.Fill (),
- Height = Dim.Fill (1),
+ Height = Dim.Fill (3),
TextAlignment = Alignment.Center
};
- var spinner = new SpinnerView { X = Pos.Center (), Y = Pos.Center (), Style = new Aesthetic () };
+ var spinner = new SpinnerView
+ {
+ X = Pos.Center (),
+ Y = Pos.Bottom (errorLabel),
+ Style = new SpinnerStyle.Aesthetic ()
+ };
spinner.AutoSpin = true;
waitIndicator.Add (errorLabel);
waitIndicator.Add (spinner);
@@ -1000,30 +724,30 @@ internal class CharMap : View, IDesignable
document.RootElement,
new
JsonSerializerOptions
- { WriteIndented = true }
+ { WriteIndented = true }
);
}
- var title = $"{ToCamelCase (name)} - {new Rune (SelectedCodePoint)} U+{SelectedCodePoint:x5}";
+ var title = $"{ToCamelCase (name!)} - {new Rune (SelectedCodePoint)} U+{SelectedCodePoint:x5}";
- var copyGlyph = new Button { Text = "Copy _Glyph" };
- var copyCP = new Button { Text = "Copy Code _Point" };
- var cancel = new Button { Text = "Cancel" };
+ Button? copyGlyph = new () { Text = "Copy _Glyph" };
+ Button? copyCodepoint = new () { Text = "Copy Code _Point" };
+ Button? cancel = new () { Text = "Cancel" };
- var dlg = new Dialog { Title = title, Buttons = [copyGlyph, copyCP, cancel] };
+ var dlg = new Dialog { Title = title, Buttons = [copyGlyph, copyCodepoint, cancel] };
copyGlyph.Accepting += (s, a) =>
{
CopyGlyph ();
- dlg.RequestStop ();
+ dlg!.RequestStop ();
};
- copyCP.Accepting += (s, a) =>
- {
- CopyCodePoint ();
- dlg.RequestStop ();
- };
- cancel.Accepting += (s, a) => dlg.RequestStop ();
+ copyCodepoint.Accepting += (s, a) =>
+ {
+ CopyCodePoint ();
+ dlg!.RequestStop ();
+ };
+ cancel.Accepting += (s, a) => dlg!.RequestStop ();
var rune = (Rune)SelectedCodePoint;
var label = new Label { Text = "IsAscii: ", X = 0, Y = 0 };
@@ -1097,129 +821,13 @@ internal class CharMap : View, IDesignable
MessageBox.ErrorQuery (
"Code Point API",
$"{UcdApiClient.BaseUrl}codepoint/dec/{SelectedCodePoint} did not return a result for\r\n {new Rune (SelectedCodePoint)} U+{SelectedCodePoint:x5}.",
- "Ok"
+ "_Ok"
);
}
// BUGBUG: This is a workaround for some weird ScrollView related mouse grab bug
Application.GrabMouse (this);
}
-}
-
-public class UcdApiClient
-{
- public const string BaseUrl = "https://ucdapi.org/unicode/latest/";
- private static readonly HttpClient _httpClient = new ();
-
- public async Task GetChars (string chars)
- {
- HttpResponseMessage response = await _httpClient.GetAsync ($"{BaseUrl}chars/{Uri.EscapeDataString (chars)}");
- response.EnsureSuccessStatusCode ();
-
- return await response.Content.ReadAsStringAsync ();
- }
-
- public async Task GetCharsName (string chars)
- {
- HttpResponseMessage response =
- await _httpClient.GetAsync ($"{BaseUrl}chars/{Uri.EscapeDataString (chars)}/name");
- response.EnsureSuccessStatusCode ();
-
- return await response.Content.ReadAsStringAsync ();
- }
-
- public async Task GetCodepointDec (int dec)
- {
- HttpResponseMessage response = await _httpClient.GetAsync ($"{BaseUrl}codepoint/dec/{dec}");
- response.EnsureSuccessStatusCode ();
-
- return await response.Content.ReadAsStringAsync ();
- }
-
- public async Task GetCodepointHex (string hex)
- {
- HttpResponseMessage response = await _httpClient.GetAsync ($"{BaseUrl}codepoint/hex/{hex}");
- response.EnsureSuccessStatusCode ();
-
- return await response.Content.ReadAsStringAsync ();
- }
-}
-
-internal class UnicodeRange
-{
- public static List Ranges = GetRanges ();
-
- public string Category;
- public int End;
- public int Start;
-
- public UnicodeRange (int start, int end, string category)
- {
- Start = start;
- End = end;
- Category = category;
- }
-
- public static List GetRanges ()
- {
- IEnumerable ranges =
- from r in typeof (UnicodeRanges).GetProperties (BindingFlags.Static | BindingFlags.Public)
- let urange = r.GetValue (null) as System.Text.Unicode.UnicodeRange
- let name = string.IsNullOrEmpty (r.Name)
- ? $"U+{urange.FirstCodePoint:x5}-U+{urange.FirstCodePoint + urange.Length:x5}"
- : r.Name
- where name != "None" && name != "All"
- select new UnicodeRange (urange.FirstCodePoint, urange.FirstCodePoint + urange.Length, name);
-
- // .NET 8.0 only supports BMP in UnicodeRanges: https://learn.microsoft.com/en-us/dotnet/api/system.text.unicode.unicoderanges?view=net-8.0
- List nonBmpRanges = new ()
- {
- new (
- 0x1F130,
- 0x1F149,
- "Squared Latin Capital Letters"
- ),
- new (
- 0x12400,
- 0x1240f,
- "Cuneiform Numbers and Punctuation"
- ),
- new (0x10000, 0x1007F, "Linear B Syllabary"),
- new (0x10080, 0x100FF, "Linear B Ideograms"),
- new (0x10100, 0x1013F, "Aegean Numbers"),
- new (0x10300, 0x1032F, "Old Italic"),
- new (0x10330, 0x1034F, "Gothic"),
- new (0x10380, 0x1039F, "Ugaritic"),
- new (0x10400, 0x1044F, "Deseret"),
- new (0x10450, 0x1047F, "Shavian"),
- new (0x10480, 0x104AF, "Osmanya"),
- new (0x10800, 0x1083F, "Cypriot Syllabary"),
- new (
- 0x1D000,
- 0x1D0FF,
- "Byzantine Musical Symbols"
- ),
- new (0x1D100, 0x1D1FF, "Musical Symbols"),
- new (0x1D300, 0x1D35F, "Tai Xuan Jing Symbols"),
- new (
- 0x1D400,
- 0x1D7FF,
- "Mathematical Alphanumeric Symbols"
- ),
- new (0x1F600, 0x1F532, "Emojis Symbols"),
- new (
- 0x20000,
- 0x2A6DF,
- "CJK Unified Ideographs Extension B"
- ),
- new (
- 0x2F800,
- 0x2FA1F,
- "CJK Compatibility Ideographs Supplement"
- ),
- new (0xE0000, 0xE007F, "Tags")
- };
-
- return ranges.Concat (nonBmpRanges).OrderBy (r => r.Category).ToList ();
- }
+
+ #endregion Details Dialog
}
diff --git a/UICatalog/Scenarios/CharacterMap/CharacterMap.cs b/UICatalog/Scenarios/CharacterMap/CharacterMap.cs
new file mode 100644
index 000000000..3456ade77
--- /dev/null
+++ b/UICatalog/Scenarios/CharacterMap/CharacterMap.cs
@@ -0,0 +1,342 @@
+#nullable enable
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using Terminal.Gui;
+
+namespace UICatalog.Scenarios;
+
+///
+/// This Scenario demonstrates building a custom control (a class deriving from View) that: - Provides a
+/// "Character Map" application (like Windows' charmap.exe). - Helps test unicode character rendering in Terminal.Gui -
+/// Illustrates how to do infinite scrolling
+///
+///
+/// See .
+///
+[ScenarioMetadata ("Character Map", "Unicode viewer. Demos infinite content drawing and scrolling.")]
+[ScenarioCategory ("Text and Formatting")]
+[ScenarioCategory ("Drawing")]
+[ScenarioCategory ("Controls")]
+[ScenarioCategory ("Layout")]
+[ScenarioCategory ("Scrolling")]
+public class CharacterMap : Scenario
+{
+ private Label? _errorLabel;
+ private TableView? _categoryList;
+ private CharMap? _charMap;
+
+ // Don't create a Window, just return the top-level view
+ public override void Main ()
+ {
+ Application.Init ();
+
+ var top = new Window
+ {
+ BorderStyle = LineStyle.None
+ };
+
+ _charMap = new ()
+ {
+ X = 0,
+ Y = 1,
+ Width = Dim.Fill (Dim.Func (() => _categoryList!.Frame.Width)),
+ Height = Dim.Fill ()
+ };
+ top.Add (_charMap);
+
+ var jumpLabel = new Label
+ {
+ X = Pos.Right (_charMap) + 1,
+ Y = Pos.Y (_charMap),
+ HotKeySpecifier = (Rune)'_',
+ Text = "_Jump To:"
+ };
+ top.Add (jumpLabel);
+
+ var jumpEdit = new TextField
+ {
+ X = Pos.Right (jumpLabel) + 1,
+ Y = Pos.Y (_charMap),
+ Width = 17,
+ Caption = "e.g. 01BE3 or ✈",
+ };
+ top.Add (jumpEdit);
+
+ _charMap.SelectedCodePointChanged += (sender, args) => jumpEdit.Text = ((Rune)args.CurrentValue).ToString ();
+
+ _errorLabel = new ()
+ {
+ X = Pos.Right (jumpEdit) + 1,
+ Y = Pos.Y (_charMap),
+ ColorScheme = Colors.ColorSchemes ["error"],
+ Text = "err",
+ Visible = false
+
+ };
+ top.Add (_errorLabel);
+
+ jumpEdit.Accepting += JumpEditOnAccept;
+
+ _categoryList = new () {
+ X = Pos.Right (_charMap),
+ Y = Pos.Bottom (jumpLabel),
+ Height = Dim.Fill (),
+ };
+ _categoryList.FullRowSelect = true;
+ _categoryList.MultiSelect = false;
+
+ _categoryList.Style.ShowVerticalCellLines = false;
+ _categoryList.Style.AlwaysShowHeaders = true;
+
+ var isDescending = false;
+
+ _categoryList.Table = CreateCategoryTable (0, isDescending);
+
+ // if user clicks the mouse in TableView
+ _categoryList.MouseClick += (s, e) =>
+ {
+ _categoryList.ScreenToCell (e.Position, out int? clickedCol);
+
+ if (clickedCol != null && e.Flags.HasFlag (MouseFlags.Button1Clicked))
+ {
+ EnumerableTableSource table = (EnumerableTableSource)_categoryList.Table;
+ string prevSelection = table.Data.ElementAt (_categoryList.SelectedRow).Category;
+ isDescending = !isDescending;
+
+ _categoryList.Table = CreateCategoryTable (clickedCol.Value, isDescending);
+
+ table = (EnumerableTableSource)_categoryList.Table;
+
+ _categoryList.SelectedRow = table.Data
+ .Select ((item, index) => new { item, index })
+ .FirstOrDefault (x => x.item.Category == prevSelection)
+ ?.index
+ ?? -1;
+ }
+ };
+
+ int longestName = UnicodeRange.Ranges.Max (r => r.Category.GetColumns ());
+
+ _categoryList.Style.ColumnStyles.Add (
+ 0,
+ new () { MaxWidth = longestName, MinWidth = longestName, MinAcceptableWidth = longestName }
+ );
+ _categoryList.Style.ColumnStyles.Add (1, new () { MaxWidth = 1, MinWidth = 6 });
+ _categoryList.Style.ColumnStyles.Add (2, new () { MaxWidth = 1, MinWidth = 6 });
+
+ _categoryList.Width = _categoryList.Style.ColumnStyles.Sum (c => c.Value.MinWidth) + 4;
+
+ _categoryList.SelectedCellChanged += (s, args) =>
+ {
+ EnumerableTableSource table = (EnumerableTableSource)_categoryList.Table;
+ _charMap.StartCodePoint = table.Data.ToArray () [args.NewRow].Start;
+ jumpEdit.Text = $"U+{_charMap.SelectedCodePoint:x5}";
+ };
+
+ top.Add (_categoryList);
+
+ var menu = new MenuBar
+ {
+ Menus =
+ [
+ new (
+ "_File",
+ new MenuItem []
+ {
+ new (
+ "_Quit",
+ $"{Application.QuitKey}",
+ () => Application.RequestStop ()
+ )
+ }
+ ),
+ new (
+ "_Options",
+ new [] { CreateMenuShowWidth () }
+ )
+ ]
+ };
+ top.Add (menu);
+
+ _charMap.SelectedCodePoint = 0;
+ _charMap.SetFocus ();
+
+ Application.Run (top);
+ top.Dispose ();
+ Application.Shutdown ();
+
+ return;
+
+ void JumpEditOnAccept (object? sender, CommandEventArgs e)
+ {
+ if (jumpEdit.Text.Length == 0)
+ {
+ return;
+ }
+
+ _errorLabel.Visible = true;
+
+ uint result = 0;
+
+ if (jumpEdit.Text.Length == 1)
+ {
+ result = (uint)jumpEdit.Text.ToRunes () [0].Value;
+ }
+ else if (jumpEdit.Text.StartsWith ("U+", StringComparison.OrdinalIgnoreCase) || jumpEdit.Text.StartsWith ("\\u"))
+ {
+ try
+ {
+ result = uint.Parse (jumpEdit.Text [2..], NumberStyles.HexNumber);
+ }
+ catch (FormatException)
+ {
+ _errorLabel.Text = "Invalid hex value";
+
+ return;
+ }
+ }
+ else if (jumpEdit.Text.StartsWith ("0", StringComparison.OrdinalIgnoreCase) || jumpEdit.Text.StartsWith ("\\u"))
+ {
+ try
+ {
+ result = uint.Parse (jumpEdit.Text, NumberStyles.HexNumber);
+ }
+ catch (FormatException)
+ {
+ _errorLabel.Text = "Invalid hex value";
+
+ return;
+ }
+ }
+ else
+ {
+ try
+ {
+ result = uint.Parse (jumpEdit.Text, NumberStyles.Integer);
+ }
+ catch (FormatException)
+ {
+ _errorLabel.Text = "Invalid value";
+
+ return;
+ }
+ }
+
+ if (result > RuneExtensions.MaxUnicodeCodePoint)
+ {
+ _errorLabel.Text = "Beyond maximum codepoint";
+
+ return;
+ }
+
+ _errorLabel.Visible = false;
+
+ EnumerableTableSource table = (EnumerableTableSource)_categoryList!.Table;
+
+ _categoryList.SelectedRow = table.Data
+ .Select ((item, index) => new { item, index })
+ .FirstOrDefault (x => x.item.Start <= result && x.item.End >= result)
+ ?.index
+ ?? -1;
+ _categoryList.EnsureSelectedCellIsVisible ();
+
+ // Ensure the typed glyph is selected
+ _charMap.SelectedCodePoint = (int)result;
+ _charMap.SetFocus ();
+
+ // Cancel the event to prevent ENTER from being handled elsewhere
+ e.Cancel = true;
+ }
+ }
+
+ private EnumerableTableSource CreateCategoryTable (int sortByColumn, bool descending)
+ {
+ Func orderBy;
+ var categorySort = string.Empty;
+ var startSort = string.Empty;
+ var endSort = string.Empty;
+
+ string sortIndicator = descending ? CM.Glyphs.DownArrow.ToString () : CM.Glyphs.UpArrow.ToString ();
+
+ switch (sortByColumn)
+ {
+ case 0:
+ orderBy = r => r.Category;
+ categorySort = sortIndicator;
+
+ break;
+ case 1:
+ orderBy = r => r.Start;
+ startSort = sortIndicator;
+
+ break;
+ case 2:
+ orderBy = r => r.End;
+ endSort = sortIndicator;
+
+ break;
+ default:
+ throw new ArgumentException ("Invalid column number.");
+ }
+
+ IOrderedEnumerable sortedRanges = descending
+ ? UnicodeRange.Ranges.OrderByDescending (orderBy)
+ : UnicodeRange.Ranges.OrderBy (orderBy);
+
+ return new (
+ sortedRanges,
+ new ()
+ {
+ { $"Category{categorySort}", s => s.Category },
+ { $"Start{startSort}", s => $"{s.Start:x5}" },
+ { $"End{endSort}", s => $"{s.End:x5}" }
+ }
+ );
+ }
+
+ private MenuItem CreateMenuShowWidth ()
+ {
+ var item = new MenuItem { Title = "_Show Glyph Width" };
+ item.CheckType |= MenuItemCheckStyle.Checked;
+ item.Checked = _charMap?.ShowGlyphWidths;
+ item.Action += () =>
+ {
+ if (_charMap is { })
+ {
+ _charMap.ShowGlyphWidths = (bool)(item.Checked = !item.Checked)!;
+ }
+ };
+
+ return item;
+ }
+
+ public override List GetDemoKeyStrokes ()
+ {
+ List keys = new ();
+
+ for (var i = 0; i < 200; i++)
+ {
+ keys.Add (Key.CursorDown);
+ }
+
+ // Category table
+ keys.Add (Key.Tab.WithShift);
+
+ // Block elements
+ keys.Add (Key.B);
+ keys.Add (Key.L);
+
+ keys.Add (Key.Tab);
+
+ for (var i = 0; i < 200; i++)
+ {
+ keys.Add (Key.CursorLeft);
+ }
+
+ return keys;
+ }
+}
diff --git a/UICatalog/Scenarios/CharacterMap/README.md b/UICatalog/Scenarios/CharacterMap/README.md
new file mode 100644
index 000000000..2901e9bf5
--- /dev/null
+++ b/UICatalog/Scenarios/CharacterMap/README.md
@@ -0,0 +1,11 @@
+# CharacterMap Scenario Deep Dive
+
+The CharacterMap Scenario is an example of the following Terminal.Gui concepts:
+
+- **Complex and High-Performnt Drawing** -
+- **Virtual Content Scrolling** -
+- **Advanced ScrollBar Control** -
+- **Unicode wide-glyph Rendering** -
+- **Advanced Layout** -
+- **Cursor Management** -
+- **Context Menu** -
\ No newline at end of file
diff --git a/UICatalog/Scenarios/CharacterMap/UcdApiClient.cs b/UICatalog/Scenarios/CharacterMap/UcdApiClient.cs
new file mode 100644
index 000000000..658a59c3c
--- /dev/null
+++ b/UICatalog/Scenarios/CharacterMap/UcdApiClient.cs
@@ -0,0 +1,48 @@
+#nullable enable
+using System;
+using System.Net.Http;
+using System.Threading.Tasks;
+
+namespace UICatalog.Scenarios;
+
+///
+/// A helper class for accessing the ucdapi.org API.
+///
+public class UcdApiClient
+{
+ public const string BaseUrl = "https://ucdapi.org/unicode/latest/";
+ private static readonly HttpClient _httpClient = new ();
+
+ public async Task GetChars (string chars)
+ {
+ HttpResponseMessage response = await _httpClient.GetAsync ($"{BaseUrl}chars/{Uri.EscapeDataString (chars)}");
+ response.EnsureSuccessStatusCode ();
+
+ return await response.Content.ReadAsStringAsync ();
+ }
+
+ public async Task GetCharsName (string chars)
+ {
+ HttpResponseMessage response =
+ await _httpClient.GetAsync ($"{BaseUrl}chars/{Uri.EscapeDataString (chars)}/name");
+ response.EnsureSuccessStatusCode ();
+
+ return await response.Content.ReadAsStringAsync ();
+ }
+
+ public async Task GetCodepointDec (int dec)
+ {
+ HttpResponseMessage response = await _httpClient.GetAsync ($"{BaseUrl}codepoint/dec/{dec}");
+ response.EnsureSuccessStatusCode ();
+
+ return await response.Content.ReadAsStringAsync ();
+ }
+
+ public async Task GetCodepointHex (string hex)
+ {
+ HttpResponseMessage response = await _httpClient.GetAsync ($"{BaseUrl}codepoint/hex/{hex}");
+ response.EnsureSuccessStatusCode ();
+
+ return await response.Content.ReadAsStringAsync ();
+ }
+}
diff --git a/UICatalog/Scenarios/CharacterMap/UnicodeRange.cs b/UICatalog/Scenarios/CharacterMap/UnicodeRange.cs
new file mode 100644
index 000000000..686823486
--- /dev/null
+++ b/UICatalog/Scenarios/CharacterMap/UnicodeRange.cs
@@ -0,0 +1,101 @@
+#nullable enable
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text.Unicode;
+
+namespace UICatalog.Scenarios;
+
+///
+/// Represents all of the Uniicode ranges.from System.Text.Unicode.UnicodeRange plus
+/// the non-BMP ranges not included.
+///
+public class UnicodeRange (int start, int end, string category)
+{
+ ///
+ /// Gets the list of all ranges.
+ ///
+ public static List Ranges => GetRanges ();
+
+ ///
+ /// The category.
+ ///
+ public string Category { get; set; } = category;
+
+ ///
+ /// Te codepoint at the start of the range.
+ ///
+ public int Start { get; set; } = start;
+
+ ///
+ /// The codepoint at the end of the range.
+ ///
+ public int End { get; set; } = end;
+
+ ///
+ /// Gets the list of all ranges..
+ ///
+ ///
+ public static List GetRanges ()
+ {
+ IEnumerable ranges =
+ from r in typeof (UnicodeRanges).GetProperties (BindingFlags.Static | BindingFlags.Public)
+ let urange = r.GetValue (null) as System.Text.Unicode.UnicodeRange
+ let name = string.IsNullOrEmpty (r.Name)
+ ? $"U+{urange.FirstCodePoint:x5}-U+{urange.FirstCodePoint + urange.Length:x5}"
+ : r.Name
+ where name != "None" && name != "All"
+ select new UnicodeRange (urange.FirstCodePoint, urange.FirstCodePoint + urange.Length, name);
+
+ // .NET 8.0 only supports BMP in UnicodeRanges: https://learn.microsoft.com/en-us/dotnet/api/system.text.unicode.unicoderanges?view=net-8.0
+ List nonBmpRanges = new ()
+ {
+ new (
+ 0x1F130,
+ 0x1F149,
+ "Squared Latin Capital Letters"
+ ),
+ new (
+ 0x12400,
+ 0x1240f,
+ "Cuneiform Numbers and Punctuation"
+ ),
+ new (0x10000, 0x1007F, "Linear B Syllabary"),
+ new (0x10080, 0x100FF, "Linear B Ideograms"),
+ new (0x10100, 0x1013F, "Aegean Numbers"),
+ new (0x10300, 0x1032F, "Old Italic"),
+ new (0x10330, 0x1034F, "Gothic"),
+ new (0x10380, 0x1039F, "Ugaritic"),
+ new (0x10400, 0x1044F, "Deseret"),
+ new (0x10450, 0x1047F, "Shavian"),
+ new (0x10480, 0x104AF, "Osmanya"),
+ new (0x10800, 0x1083F, "Cypriot Syllabary"),
+ new (
+ 0x1D000,
+ 0x1D0FF,
+ "Byzantine Musical Symbols"
+ ),
+ new (0x1D100, 0x1D1FF, "Musical Symbols"),
+ new (0x1D300, 0x1D35F, "Tai Xuan Jing Symbols"),
+ new (
+ 0x1D400,
+ 0x1D7FF,
+ "Mathematical Alphanumeric Symbols"
+ ),
+ new (0x1F600, 0x1F532, "Emojis Symbols"),
+ new (
+ 0x20000,
+ 0x2A6DF,
+ "CJK Unified Ideographs Extension B"
+ ),
+ new (
+ 0x2F800,
+ 0x2FA1F,
+ "CJK Compatibility Ideographs Supplement"
+ ),
+ new (0xE0000, 0xE007F, "Tags")
+ };
+
+ return ranges.Concat (nonBmpRanges).OrderBy (r => r.Category).ToList ();
+ }
+}
diff --git a/UICatalog/Scenarios/ScrollBarDemo.cs b/UICatalog/Scenarios/ScrollBarDemo.cs
index dc13b91c1..ca8d2f5ed 100644
--- a/UICatalog/Scenarios/ScrollBarDemo.cs
+++ b/UICatalog/Scenarios/ScrollBarDemo.cs
@@ -4,12 +4,10 @@ using Terminal.Gui;
namespace UICatalog.Scenarios;
-[ScenarioMetadata ("ScrollBar Demo", "Demonstrates using ScrollBar view.")]
+[ScenarioMetadata ("ScrollBar Demo", "Demonstrates ScrollBar.")]
[ScenarioCategory ("Scrolling")]
public class ScrollBarDemo : Scenario
{
- private ViewDiagnosticFlags _diagnosticFlags;
-
public override void Main ()
{
Application.Init ();
@@ -29,23 +27,22 @@ public class ScrollBarDemo : Scenario
X = Pos.Right (editor),
Width = Dim.Fill (),
Height = Dim.Fill (),
- ColorScheme = Colors.ColorSchemes ["Base"]
+ ColorScheme = Colors.ColorSchemes ["Base"],
+ Arrangement = ViewArrangement.Resizable
};
+ frameView!.Padding!.Thickness = new (1);
+ frameView.Padding.Diagnostics = ViewDiagnosticFlags.Ruler;
app.Add (frameView);
var scrollBar = new ScrollBar
{
X = Pos.AnchorEnd (),
- AutoHide = false
+ AutoHide = false,
+ Size = 100,
//ShowPercent = true
};
frameView.Add (scrollBar);
- app.Loaded += (s, e) =>
- {
- scrollBar.Size = scrollBar.Viewport.Height;
- };
-
int GetMaxLabelWidth (int groupId)
{
return frameView.Subviews.Max (
@@ -134,7 +131,6 @@ public class ScrollBarDemo : Scenario
scrollBar.Y = 0;
scrollWidthHeight.Value = Math.Min (scrollWidthHeight.Value, scrollBar.SuperView.GetContentSize ().Width);
scrollBar.Width = scrollWidthHeight.Value;
- scrollBar.Size /= 3;
}
else
{
@@ -143,7 +139,6 @@ public class ScrollBarDemo : Scenario
scrollBar.Y = Pos.AnchorEnd ();
scrollWidthHeight.Value = Math.Min (scrollWidthHeight.Value, scrollBar.SuperView.GetContentSize ().Height);
scrollBar.Height = scrollWidthHeight.Value;
- scrollBar.Size *= 3;
}
};
@@ -189,34 +184,14 @@ public class ScrollBarDemo : Scenario
};
frameView.Add (lblSliderPosition);
- NumericUpDown scrollSliderPosition = new ()
+ Label scrollSliderPosition = new ()
{
- Value = scrollBar.SliderPosition,
+ Text = scrollBar.GetSliderPosition ().ToString (),
X = Pos.Right (lblSliderPosition) + 1,
Y = Pos.Top (lblSliderPosition)
};
frameView.Add (scrollSliderPosition);
- scrollSliderPosition.ValueChanging += (s, e) =>
- {
- if (e.NewValue < 0)
- {
- e.Cancel = true;
-
- return;
- }
-
- if (scrollBar.SliderPosition != e.NewValue)
- {
- scrollBar.SliderPosition = e.NewValue;
- }
-
- if (scrollBar.SliderPosition != e.NewValue)
- {
- e.Cancel = true;
- }
- };
-
var lblContentPosition = new Label
{
Text = "_ContentPosition:",
@@ -229,7 +204,7 @@ public class ScrollBarDemo : Scenario
NumericUpDown scrollContentPosition = new ()
{
- Value = scrollBar.SliderPosition,
+ Value = scrollBar.GetSliderPosition (),
X = Pos.Right (lblContentPosition) + 1,
Y = Pos.Top (lblContentPosition)
};
@@ -342,22 +317,15 @@ public class ScrollBarDemo : Scenario
}
};
- scrollBar.SliderPositionChanging += (s, e) =>
- {
- eventLog.Log ($"SliderPositionChanging: {e.CurrentValue}");
- eventLog.Log ($" NewValue: {e.NewValue}");
- };
-
scrollBar.SliderPositionChanged += (s, e) =>
{
eventLog.Log ($"SliderPositionChanged: {e.CurrentValue}");
eventLog.Log ($" ContentPosition: {scrollBar.ContentPosition}");
- scrollSliderPosition.Value = e.CurrentValue;
+ scrollSliderPosition.Text = e.CurrentValue.ToString ();
};
editor.Initialized += (s, e) =>
{
- scrollBar.Size = int.Max (app.GetContentSize ().Height * 2, app.GetContentSize ().Width * 2);
editor.ViewToEdit = scrollBar;
};
diff --git a/UICatalog/Scenarios/ScrollDemo.cs b/UICatalog/Scenarios/ScrollDemo.cs
index fd96173f6..40c3211ea 100644
--- a/UICatalog/Scenarios/ScrollDemo.cs
+++ b/UICatalog/Scenarios/ScrollDemo.cs
@@ -1,22 +1,21 @@
using System;
+using System.Linq;
using Terminal.Gui;
namespace UICatalog.Scenarios;
-[ScenarioMetadata ("Scroll Demo", "Demonstrates using Scroll view.")]
-[ScenarioCategory ("Drawing")]
+[ScenarioMetadata ("Scroll Demo", "Demonstrates Scroll.")]
[ScenarioCategory ("Scrolling")]
public class ScrollDemo : Scenario
{
- private ViewDiagnosticFlags _diagnosticFlags;
-
public override void Main ()
{
Application.Init ();
Window app = new ()
{
- Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}"
+ Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}",
+ Arrangement = ViewArrangement.Fixed
};
var editor = new AdornmentsEditor ();
@@ -28,25 +27,40 @@ public class ScrollDemo : Scenario
X = Pos.Right (editor),
Width = Dim.Fill (),
Height = Dim.Fill (),
- ColorScheme = Colors.ColorSchemes ["Base"]
+ ColorScheme = Colors.ColorSchemes ["Base"],
+ Arrangement = ViewArrangement.Resizable
};
+ frameView.Padding.Thickness = new (1);
+ frameView.Padding.Diagnostics = ViewDiagnosticFlags.Ruler;
app.Add (frameView);
var scroll = new Scroll
{
X = Pos.AnchorEnd (),
- ShowPercent = true
+ Size = 1000,
};
frameView.Add (scroll);
- app.Loaded += (s, e) =>
- {
- scroll.Size = frameView.Viewport.Height;
- };
+ int GetMaxLabelWidth (int groupId)
+ {
+ return frameView.Subviews.Max (
+ v =>
+ {
+ if (v.Y.Has (out var pos) && pos.GroupId == groupId)
+ {
+ return v.Text.GetColumns ();
+ }
+
+ return 0;
+ });
+ }
var lblWidthHeight = new Label
{
- Text = "Width/Height:"
+ Text = "_Width/Height:",
+ TextAlignment = Alignment.End,
+ Y = Pos.Align (Alignment.Start, AlignmentModes.StartToEnd, groupId: 1),
+ Width = Dim.Func (() => GetMaxLabelWidth (1))
};
frameView.Add (lblWidthHeight);
@@ -59,71 +73,79 @@ public class ScrollDemo : Scenario
frameView.Add (scrollWidthHeight);
scrollWidthHeight.ValueChanging += (s, e) =>
- {
- if (e.NewValue < 1
- || (e.NewValue
- > (scroll.Orientation == Orientation.Vertical
- ? scroll.SuperView?.GetContentSize ().Width
- : scroll.SuperView?.GetContentSize ().Height)))
- {
- // TODO: This must be handled in the ScrollSlider if Width and Height being virtual
- e.Cancel = true;
+ {
+ if (e.NewValue < 1
+ || (e.NewValue
+ > (scroll.Orientation == Orientation.Vertical
+ ? scroll.SuperView?.GetContentSize ().Width
+ : scroll.SuperView?.GetContentSize ().Height)))
+ {
+ // TODO: This must be handled in the ScrollSlider if Width and Height being virtual
+ e.Cancel = true;
- return;
- }
+ return;
+ }
- if (scroll.Orientation == Orientation.Vertical)
- {
- scroll.Width = e.NewValue;
- }
- else
- {
- scroll.Height = e.NewValue;
- }
- };
+ if (scroll.Orientation == Orientation.Vertical)
+ {
+ scroll.Width = e.NewValue;
+ }
+ else
+ {
+ scroll.Height = e.NewValue;
+ }
+ };
+
+
+ var lblOrientationabel = new Label
+ {
+ Text = "_Orientation:",
+ TextAlignment = Alignment.End,
+ Y = Pos.Align (Alignment.Start, groupId: 1),
+ Width = Dim.Func (() => GetMaxLabelWidth (1))
+ };
+ frameView.Add (lblOrientationabel);
var rgOrientation = new RadioGroup
{
- Y = Pos.Bottom (lblWidthHeight),
+ X = Pos.Right (lblOrientationabel) + 1,
+ Y = Pos.Top (lblOrientationabel),
RadioLabels = ["Vertical", "Horizontal"],
Orientation = Orientation.Horizontal
};
frameView.Add (rgOrientation);
rgOrientation.SelectedItemChanged += (s, e) =>
- {
- if (e.SelectedItem == e.PreviousSelectedItem)
- {
- return;
- }
+ {
+ if (e.SelectedItem == e.PreviousSelectedItem)
+ {
+ return;
+ }
- if (rgOrientation.SelectedItem == 0)
- {
- scroll.Orientation = Orientation.Vertical;
- scroll.X = Pos.AnchorEnd ();
- scroll.Y = 0;
- scrollWidthHeight.Value = Math.Min (scrollWidthHeight.Value, scroll.SuperView.GetContentSize ().Width);
- scroll.Width = scrollWidthHeight.Value;
- scroll.Height = Dim.Fill ();
- scroll.Size /= 3;
- }
- else
- {
- scroll.Orientation = Orientation.Horizontal;
- scroll.X = 0;
- scroll.Y = Pos.AnchorEnd ();
- scroll.Width = Dim.Fill ();
-
- scrollWidthHeight.Value = Math.Min (scrollWidthHeight.Value, scroll.SuperView.GetContentSize ().Height);
- scroll.Height = scrollWidthHeight.Value;
- scroll.Size *= 3;
- }
- };
+ if (rgOrientation.SelectedItem == 0)
+ {
+ scroll.Orientation = Orientation.Vertical;
+ scroll.X = Pos.AnchorEnd ();
+ scroll.Y = 0;
+ scrollWidthHeight.Value = Math.Min (scrollWidthHeight.Value, scroll.SuperView.GetContentSize ().Width);
+ scroll.Width = scrollWidthHeight.Value;
+ }
+ else
+ {
+ scroll.Orientation = Orientation.Horizontal;
+ scroll.X = 0;
+ scroll.Y = Pos.AnchorEnd ();
+ scrollWidthHeight.Value = Math.Min (scrollWidthHeight.Value, scroll.SuperView.GetContentSize ().Height);
+ scroll.Height = scrollWidthHeight.Value;
+ }
+ };
var lblSize = new Label
{
- Y = Pos.Bottom (rgOrientation),
- Text = "Size:"
+ Text = "_Size:",
+ TextAlignment = Alignment.End,
+ Y = Pos.Align (Alignment.Start, groupId: 1),
+ Width = Dim.Func (() => GetMaxLabelWidth (1))
};
frameView.Add (lblSize);
@@ -133,106 +155,109 @@ public class ScrollDemo : Scenario
X = Pos.Right (lblSize) + 1,
Y = Pos.Top (lblSize)
};
- scroll.SizeChanged += (sender, args) => scrollSize.Value = args.CurrentValue;
frameView.Add (scrollSize);
scrollSize.ValueChanging += (s, e) =>
- {
- if (e.NewValue < 0)
- {
- e.Cancel = true;
-
- return;
- }
-
- if (scroll.Size != e.NewValue)
- {
- scroll.Size = e.NewValue;
- }
- };
-
- var lblPosition = new Label
{
- Y = Pos.Bottom (lblSize),
- Text = "Position:"
- };
- frameView.Add (lblPosition);
+ if (e.NewValue < 0)
+ {
+ e.Cancel = true;
- NumericUpDown scrollPosition = new ()
+ return;
+ }
+
+ if (scroll.Size != e.NewValue)
+ {
+ scroll.Size = e.NewValue;
+ }
+ };
+
+ var lblSliderPosition = new Label
{
- Value = scroll.SliderPosition,
- X = Pos.Right (lblPosition) + 1,
- Y = Pos.Top (lblPosition)
+ Text = "_SliderPosition:",
+ TextAlignment = Alignment.End,
+ Y = Pos.Align (Alignment.Start, groupId: 1),
+ Width = Dim.Func (() => GetMaxLabelWidth (1))
+
};
- frameView.Add (scrollPosition);
+ frameView.Add (lblSliderPosition);
- scrollPosition.ValueChanging += (s, e) =>
- {
- if (e.NewValue < 0)
- {
- e.Cancel = true;
+ Label scrollSliderPosition = new ()
+ {
+ Text = scroll.GetSliderPosition ().ToString (),
+ X = Pos.Right (lblSliderPosition) + 1,
+ Y = Pos.Top (lblSliderPosition)
+ };
+ frameView.Add (scrollSliderPosition);
- return;
- }
+ var lblContentPosition = new Label
+ {
+ Text = "_ContentPosition:",
+ TextAlignment = Alignment.End,
+ Y = Pos.Align (Alignment.Start, groupId: 1),
+ Width = Dim.Func (() => GetMaxLabelWidth (1))
- if (scroll.SliderPosition != e.NewValue)
- {
- scroll.SliderPosition = e.NewValue;
- }
+ };
+ frameView.Add (lblContentPosition);
- if (scroll.SliderPosition != e.NewValue)
- {
- e.Cancel = true;
- }
- };
+ NumericUpDown scrollContentPosition = new ()
+ {
+ Value = scroll.GetSliderPosition (),
+ X = Pos.Right (lblContentPosition) + 1,
+ Y = Pos.Top (lblContentPosition)
+ };
+ frameView.Add (scrollContentPosition);
+
+ scrollContentPosition.ValueChanging += (s, e) =>
+ {
+ if (e.NewValue < 0)
+ {
+ e.Cancel = true;
+
+ return;
+ }
+
+ if (scroll.ContentPosition != e.NewValue)
+ {
+ scroll.ContentPosition = e.NewValue;
+ }
+
+ if (scroll.ContentPosition != e.NewValue)
+ {
+ e.Cancel = true;
+ }
+ };
+
+ var lblOptions = new Label
+ {
+ Text = "_Options:",
+ TextAlignment = Alignment.End,
+ Y = Pos.Align (Alignment.Start, groupId: 1),
+ Width = Dim.Func (() => GetMaxLabelWidth (1))
+ };
+ frameView.Add (lblOptions);
+
+ var ckbShowPercent = new CheckBox
+ {
+ Y = Pos.Top (lblOptions),
+ X = Pos.Right (lblOptions) + 1,
+ Text = "Sho_wPercent",
+ CheckedState = scroll.ShowPercent ? CheckState.Checked : CheckState.UnChecked
+ };
+ ckbShowPercent.CheckedStateChanging += (s, e) => scroll.ShowPercent = e.NewValue == CheckState.Checked;
+ frameView.Add (ckbShowPercent);
//var ckbKeepContentInAllViewport = new CheckBox
//{
- // Y = Pos.Bottom (scrollPosition), Text = "KeepContentInAllViewport",
- // CheckedState = scroll.KeepContentInAllViewport ? CheckState.Checked : CheckState.UnChecked
+ // X = Pos.Right (ckbShowScrollIndicator) + 1, Y = Pos.Bottom (scrollPosition), Text = "KeepContentInAllViewport",
+ // CheckedState = Scroll.KeepContentInAllViewport ? CheckState.Checked : CheckState.UnChecked
//};
- //ckbKeepContentInAllViewport.CheckedStateChanging += (s, e) => scroll.KeepContentInAllViewport = e.NewValue == CheckState.Checked;
+ //ckbKeepContentInAllViewport.CheckedStateChanging += (s, e) => Scroll.KeepContentInAllViewport = e.NewValue == CheckState.Checked;
//view.Add (ckbKeepContentInAllViewport);
- var lblSizeChanged = new Label
- {
- Y = Pos.Bottom (scrollPosition) + 1
- };
- frameView.Add (lblSizeChanged);
-
- scroll.SizeChanged += (s, e) =>
- {
- lblSizeChanged.Text = $"SizeChanged event - CurrentValue: {e.CurrentValue}";
-
- if (scrollSize.Value != e.CurrentValue)
- {
- scrollSize.Value = e.CurrentValue;
- }
- };
-
- var lblPosChanging = new Label
- {
- Y = Pos.Bottom (lblSizeChanged)
- };
- frameView.Add (lblPosChanging);
-
- scroll.SliderPositionChanging += (s, e) => { lblPosChanging.Text = $"PositionChanging event - CurrentValue: {e.CurrentValue}; NewValue: {e.NewValue}"; };
-
- var lblPositionChanged = new Label
- {
- Y = Pos.Bottom (lblPosChanging)
- };
- frameView.Add (lblPositionChanged);
-
- scroll.SliderPositionChanged += (s, e) =>
- {
- lblPositionChanged.Text = $"PositionChanged event - CurrentValue: {e.CurrentValue}";
- scrollPosition.Value = e.CurrentValue;
- };
-
var lblScrollFrame = new Label
{
- Y = Pos.Bottom (lblPositionChanged) + 1
+ Y = Pos.Bottom (lblOptions) + 1
};
frameView.Add (lblScrollFrame);
@@ -248,21 +273,59 @@ public class ScrollDemo : Scenario
};
frameView.Add (lblScrollContentSize);
-
scroll.SubviewsLaidOut += (s, e) =>
- {
- lblScrollFrame.Text = $"Scroll Frame: {scroll.Frame.ToString ()}";
- lblScrollViewport.Text = $"Scroll Viewport: {scroll.Viewport.ToString ()}";
- lblScrollContentSize.Text = $"Scroll ContentSize: {scroll.GetContentSize ().ToString ()}";
- };
+ {
+ lblScrollFrame.Text = $"Scroll Frame: {scroll.Frame.ToString ()}";
+ lblScrollViewport.Text = $"Scroll Viewport: {scroll.Viewport.ToString ()}";
+ lblScrollContentSize.Text = $"Scroll ContentSize: {scroll.GetContentSize ().ToString ()}";
+ };
- editor.Initialized += (s, e) =>
- {
- scroll.Size = int.Max (app.GetContentSize ().Height * 2, app.GetContentSize ().Width * 2);
- editor.ViewToEdit = scroll;
- };
+ EventLog eventLog = new ()
+ {
+ X = Pos.AnchorEnd () - 1,
+ Y = 0,
+ Height = Dim.Height (frameView),
+ BorderStyle = LineStyle.Single,
+ ViewToLog = scroll
+ };
+ app.Add (eventLog);
+ frameView.Width = Dim.Fill (Dim.Func (() => Math.Max (28, eventLog.Frame.Width + 1)));
- app.Closed += (s, e) => View.Diagnostics = _diagnosticFlags;
+ app.Initialized += AppOnInitialized;
+
+
+ void AppOnInitialized (object sender, EventArgs e)
+ {
+ scroll.SizeChanged += (s, e) =>
+ {
+ eventLog.Log ($"SizeChanged: {e.CurrentValue}");
+
+ if (scrollSize.Value != e.CurrentValue)
+ {
+ scrollSize.Value = e.CurrentValue;
+ }
+ };
+
+ scroll.SliderPositionChanged += (s, e) =>
+ {
+ eventLog.Log ($"SliderPositionChanged: {e.CurrentValue}");
+ eventLog.Log ($" ContentPosition: {scroll.ContentPosition}");
+ scrollSliderPosition.Text = e.CurrentValue.ToString ();
+ };
+
+ scroll.ContentPositionChanged += (s, e) =>
+ {
+ eventLog.Log ($"SliderPositionChanged: {e.CurrentValue}");
+ eventLog.Log ($" ContentPosition: {scroll.ContentPosition}");
+ scrollContentPosition.Value = e.CurrentValue;
+ };
+
+ editor.Initialized += (s, e) =>
+ {
+ editor.ViewToEdit = scroll;
+ };
+
+ }
Application.Run (app);
app.Dispose ();
diff --git a/UICatalog/Scenarios/TableEditor.cs b/UICatalog/Scenarios/TableEditor.cs
index e76900bca..e1407506a 100644
--- a/UICatalog/Scenarios/TableEditor.cs
+++ b/UICatalog/Scenarios/TableEditor.cs
@@ -65,8 +65,8 @@ public class TableEditor : Scenario
"Cuneiform Numbers and Punctuation"
),
new (
- (uint)(CharMap._maxCodePoint - 16),
- (uint)CharMap._maxCodePoint,
+ (uint)(UICatalog.Scenarios.UnicodeRange.Ranges.Max (r => r.End) - 16),
+ (uint)UICatalog.Scenarios.UnicodeRange.Ranges.Max (r => r.End),
"End"
),
new (0x0020, 0x007F, "Basic Latin"),
@@ -1533,17 +1533,10 @@ public class TableEditor : Scenario
);
}
- private class UnicodeRange
+ public class UnicodeRange (uint start, uint end, string category)
{
- public readonly string Category;
- public readonly uint End;
- public readonly uint Start;
-
- public UnicodeRange (uint start, uint end, string category)
- {
- Start = start;
- End = end;
- Category = category;
- }
+ public readonly string Category = category;
+ public readonly uint End = end;
+ public readonly uint Start = start;
}
}
diff --git a/UnitTests/Views/ScrollBarTests.cs b/UnitTests/Views/ScrollBarTests.cs
index 460ea18bf..a0e177fce 100644
--- a/UnitTests/Views/ScrollBarTests.cs
+++ b/UnitTests/Views/ScrollBarTests.cs
@@ -52,7 +52,7 @@ public class ScrollBarTests
Assert.False (scrollBar.CanFocus);
Assert.Equal (Orientation.Vertical, scrollBar.Orientation);
Assert.Equal (0, scrollBar.Size);
- Assert.Equal (0, scrollBar.SliderPosition);
+ Assert.Equal (0, scrollBar.GetSliderPosition ());
Assert.True (scrollBar.AutoHide);
}
@@ -82,43 +82,10 @@ public class ScrollBarTests
};
super.Add (scrollBar);
scrollBar.Layout ();
- scrollBar.SliderPosition = 1;
+ scrollBar.ContentPosition = 1;
scrollBar.Orientation = Orientation.Horizontal;
- Assert.Equal (0, scrollBar.SliderPosition);
- }
-
-
- [Fact]
- public void SliderPosition_Event_Cancelables ()
- {
- var changingCount = 0;
- var changedCount = 0;
- var scrollBar = new ScrollBar { };
- scrollBar.Layout ();
- scrollBar.Size = scrollBar.Viewport.Height * 2;
- scrollBar.Layout ();
-
- scrollBar.SliderPositionChanging += (s, e) =>
- {
- if (changingCount == 0)
- {
- e.Cancel = true;
- }
-
- changingCount++;
- };
- scrollBar.SliderPositionChanged += (s, e) => changedCount++;
-
- scrollBar.SliderPosition = 1;
- Assert.Equal (0, scrollBar.SliderPosition);
- Assert.Equal (1, changingCount);
- Assert.Equal (0, changedCount);
-
- scrollBar.SliderPosition = 1;
- Assert.Equal (1, scrollBar.SliderPosition);
- Assert.Equal (2, changingCount);
- Assert.Equal (1, changedCount);
+ Assert.Equal (0, scrollBar.GetSliderPosition ());
}
@@ -179,10 +146,10 @@ public class ScrollBarTests
Assert.Equal (30, scrollBar.Size);
scrollBar.KeepContentInAllViewport = false;
- scrollBar.SliderPosition = 50;
- Assert.Equal (scrollBar.SliderPosition, scrollBar.Size - 1);
- Assert.Equal (scrollBar.SliderPosition, view.Viewport.Y);
- Assert.Equal (29, scrollBar.SliderPosition);
+ scrollBar.ContentPosition = 50;
+ Assert.Equal (scrollBar.GetSliderPosition (), scrollBar.Size - 1);
+ Assert.Equal (scrollBar.GetSliderPosition (), view.Viewport.Y);
+ Assert.Equal (29, scrollBar.GetSliderPosition ());
Assert.Equal (29, view.Viewport.Y);
top.Dispose ();
@@ -198,7 +165,7 @@ public class ScrollBarTests
var scrollBar = new ScrollBar
{
X = 10, Y = 10, Width = orientation == Orientation.Vertical ? 1 : 10, Height = orientation == Orientation.Vertical ? 10 : 1, Size = 20,
- SliderPosition = 5, Orientation = orientation, KeepContentInAllViewport = true
+ ContentPosition = 5, Orientation = orientation, KeepContentInAllViewport = true
};
var top = new Toplevel ();
top.Add (scrollBar);
@@ -346,7 +313,7 @@ public class ScrollBarTests
scrollBar.Size = sliderSize;
scrollBar.Layout ();
- scrollBar.SliderPosition = sliderPosition;
+ scrollBar.ContentPosition = sliderPosition;
super.BeginInit ();
super.EndInit ();
@@ -392,10 +359,10 @@ public class ScrollBarTests
top.Add (scrollBar);
RunState rs = Application.Begin (top);
- scrollBar.SliderPosition = 5;
+ scrollBar.ContentPosition = 5;
Application.RunIteration (ref rs);
- Assert.Equal (5, scrollBar.SliderPosition);
+ Assert.Equal (5, scrollBar.GetSliderPosition ());
Assert.Equal (12, scrollBar.ContentPosition);
int initialPos = scrollBar.ContentPosition;
@@ -433,10 +400,10 @@ public class ScrollBarTests
top.Add (scrollBar);
RunState rs = Application.Begin (top);
- scrollBar.SliderPosition = 0;
+ scrollBar.ContentPosition = 0;
Application.RunIteration (ref rs);
- Assert.Equal (0, scrollBar.SliderPosition);
+ Assert.Equal (0, scrollBar.GetSliderPosition ());
Assert.Equal (0, scrollBar.ContentPosition);
int initialPos = scrollBar.ContentPosition;
diff --git a/UnitTests/Views/ScrollTests.cs b/UnitTests/Views/ScrollTests.cs
index 7afb6afc8..00b7481e7 100644
--- a/UnitTests/Views/ScrollTests.cs
+++ b/UnitTests/Views/ScrollTests.cs
@@ -21,7 +21,7 @@ public class ScrollTests
}
[Fact]
- public void OnOrientationChanged_Sets_Position_To_0 ()
+ public void OnOrientationChanged_Sets_ContentPosition_To_0 ()
{
View super = new View ()
{
@@ -34,10 +34,10 @@ public class ScrollTests
};
super.Add (scroll);
scroll.Layout ();
- scroll.SliderPosition = 1;
+ scroll.ContentPosition = 1;
scroll.Orientation = Orientation.Horizontal;
- Assert.Equal (0, scroll.SliderPosition);
+ Assert.Equal (0, scroll.ContentPosition);
}
@@ -224,7 +224,7 @@ public class ScrollTests
Assert.False (scroll.CanFocus);
Assert.Equal (Orientation.Vertical, scroll.Orientation);
Assert.Equal (0, scroll.Size);
- Assert.Equal (0, scroll.SliderPosition);
+ Assert.Equal (0, scroll.GetSliderPosition ());
}
//[Fact]
@@ -324,7 +324,7 @@ public class ScrollTests
top.Add (scroll);
RunState rs = Application.Begin (top);
- Assert.Equal (0, scroll.SliderPosition);
+ Assert.Equal (0, scroll.GetSliderPosition ());
Assert.Equal (0, scroll.ContentPosition);
Application.RaiseMouseEvent (new ()
@@ -377,10 +377,10 @@ public class ScrollTests
top.Add (scroll);
RunState rs = Application.Begin (top);
- scroll.SliderPosition = 5;
+ scroll.ContentPosition = 5;
Application.RunIteration (ref rs);
- Assert.Equal (5, scroll.SliderPosition);
+ Assert.Equal (5, scroll.GetSliderPosition ());
Assert.Equal (10, scroll.ContentPosition);
Application.RaiseMouseEvent (new ()
@@ -390,7 +390,7 @@ public class ScrollTests
});
Application.RunIteration (ref rs);
- Assert.Equal (0, scroll.SliderPosition);
+ Assert.Equal (0, scroll.GetSliderPosition ());
Assert.Equal (0, scroll.ContentPosition);
Application.ResetState (true);
@@ -421,42 +421,10 @@ public class ScrollTests
scroll.Size = scrollSize;
super.Layout ();
- scroll.SliderPosition = scrollPosition;
+ scroll.ContentPosition = scrollPosition;
super.Layout ();
- Assert.True (scroll.SliderPosition <= scrollSize);
- }
-
- [Fact]
- public void SliderPosition_Event_Cancelables ()
- {
- var changingCount = 0;
- var changedCount = 0;
- var scroll = new Scroll { };
- scroll.Layout ();
- scroll.Size = scroll.Viewport.Height * 2;
- scroll.Layout ();
-
- scroll.SliderPositionChanging += (s, e) =>
- {
- if (changingCount == 0)
- {
- e.Cancel = true;
- }
-
- changingCount++;
- };
- scroll.SliderPositionChanged += (s, e) => changedCount++;
-
- scroll.SliderPosition = 1;
- Assert.Equal (0, scroll.SliderPosition);
- Assert.Equal (1, changingCount);
- Assert.Equal (0, changedCount);
-
- scroll.SliderPosition = 1;
- Assert.Equal (1, scroll.SliderPosition);
- Assert.Equal (2, changingCount);
- Assert.Equal (1, changedCount);
+ Assert.True (scroll.GetSliderPosition () <= scrollSize);
}
[Fact]
@@ -466,60 +434,52 @@ public class ScrollTests
var cancel = false;
var changed = 0;
var scroll = new Scroll { Height = 10, Size = 20 };
- scroll.SliderPositionChanging += Scroll_PositionChanging;
scroll.SliderPositionChanged += Scroll_PositionChanged;
Assert.Equal (Orientation.Vertical, scroll.Orientation);
scroll.Layout ();
Assert.Equal (new (0, 0, 1, 10), scroll.Viewport);
- Assert.Equal (0, scroll.SliderPosition);
+ Assert.Equal (0, scroll.GetSliderPosition ());
Assert.Equal (0, changing);
Assert.Equal (0, changed);
- scroll.SliderPosition = 0;
- Assert.Equal (0, scroll.SliderPosition);
+ scroll.ContentPosition = 0;
+ Assert.Equal (0, scroll.GetSliderPosition ());
Assert.Equal (0, changing);
Assert.Equal (0, changed);
- scroll.SliderPosition = 1;
- Assert.Equal (1, scroll.SliderPosition);
+ scroll.ContentPosition = 1;
+ Assert.Equal (1, scroll.GetSliderPosition ());
Assert.Equal (1, changing);
Assert.Equal (1, changed);
Reset ();
cancel = true;
- scroll.SliderPosition = 2;
- Assert.Equal (1, scroll.SliderPosition);
+ scroll.ContentPosition = 2;
+ Assert.Equal (1, scroll.GetSliderPosition ());
Assert.Equal (1, changing);
Assert.Equal (0, changed);
Reset ();
- scroll.SliderPosition = 10;
- Assert.Equal (5, scroll.SliderPosition);
+ scroll.ContentPosition = 10;
+ Assert.Equal (5, scroll.GetSliderPosition ());
Assert.Equal (1, changing);
Assert.Equal (1, changed);
Reset ();
- scroll.SliderPosition = 11;
- Assert.Equal (5, scroll.SliderPosition);
+ scroll.ContentPosition = 11;
+ Assert.Equal (5, scroll.GetSliderPosition ());
Assert.Equal (1, changing);
Assert.Equal (1, changed);
Reset ();
- scroll.SliderPosition = 0;
- Assert.Equal (0, scroll.SliderPosition);
+ scroll.ContentPosition = 0;
+ Assert.Equal (0, scroll.GetSliderPosition ());
Assert.Equal (1, changing);
Assert.Equal (1, changed);
- scroll.SliderPositionChanging -= Scroll_PositionChanging;
scroll.SliderPositionChanged -= Scroll_PositionChanged;
- void Scroll_PositionChanging (object sender, CancelEventArgs e)
- {
- changing++;
- e.Cancel = cancel;
- }
-
void Scroll_PositionChanged (object sender, EventArgs e) { changed++; }
void Reset ()
@@ -625,7 +585,7 @@ public class ScrollTests
scroll.Size = sliderSize;
scroll.Layout ();
- scroll.SliderPosition = sliderPosition;
+ scroll.ContentPosition = sliderPosition;
super.BeginInit ();
super.EndInit ();