diff --git a/Terminal.Gui/Views/SpinnerView.cs b/Terminal.Gui/Views/SpinnerView.cs deleted file mode 100644 index 6cd25d698..000000000 --- a/Terminal.Gui/Views/SpinnerView.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; - -namespace Terminal.Gui { - - /// - /// A 1x1 based on which displays a spinning - /// line character. - /// - /// - /// By default animation only occurs when you call . - /// Use to make the automate calls to . - /// - public class SpinnerView : Label { - private Rune [] _runes = new Rune [] { '|', '/', '\u2500', '\\' }; - private int _currentIdx = 0; - private DateTime _lastRender = DateTime.MinValue; - private object _timeout; - - /// - /// Gets or sets the number of milliseconds to wait between characters - /// in the spin. Defaults to 250. - /// - /// This is the maximum speed the spinner will rotate at. You still need to - /// call or to - /// advance/start animation. - public int SpinDelayInMilliseconds { get; set; } = 250; - - /// - /// Creates a new instance of the class. - /// - public SpinnerView () - { - Width = 1; Height = 1; - } - - /// - public override void Redraw (Rect bounds) - { - if (DateTime.Now - _lastRender > TimeSpan.FromMilliseconds (SpinDelayInMilliseconds)) { - _currentIdx = (_currentIdx + 1) % _runes.Length; - Text = "" + _runes [_currentIdx]; - _lastRender = DateTime.Now; - } - - base.Redraw (bounds); - } - - /// - /// Automates spinning - /// - public void AutoSpin () - { - if (_timeout != null) { - return; - } - - _timeout = Application.MainLoop.AddTimeout ( - TimeSpan.FromMilliseconds (SpinDelayInMilliseconds), (m) => { - Application.MainLoop.Invoke (this.SetNeedsDisplay); - return true; - }); - } - - /// - protected override void Dispose (bool disposing) - { - if (_timeout != null) { - Application.MainLoop.RemoveTimeout (_timeout); - _timeout = null; - } - - base.Dispose (disposing); - } - } -} \ No newline at end of file diff --git a/Terminal.Gui/Views/SpinnerView/SpinnerStyle.cs b/Terminal.Gui/Views/SpinnerView/SpinnerStyle.cs new file mode 100644 index 000000000..e8a7fc64a --- /dev/null +++ b/Terminal.Gui/Views/SpinnerView/SpinnerStyle.cs @@ -0,0 +1,1699 @@ +//------------------------------------------------------------------------------ +// SpinnerStyles below are derived from +// +// MIT License +// Copyright (c) Sindre Sorhus +// (https://sindresorhus.com) +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +//------------------------------------------------------------------------------ +// Windows Terminal supports Unicode and Emoji characters, but by default +// conhost shells (e.g., PowerShell and cmd.exe) do not. See +// . +//------------------------------------------------------------------------------ + +using System; + +namespace Terminal.Gui { + /// + /// SpinnerStyles used in a . + /// + public abstract class SpinnerStyle { + const int DEFAULT_DELAY = 80; + const bool DEFAULT_BOUNCE = false; + const bool DEFAULT_SPECIAL = false; + + /// + /// Gets or sets the number of milliseconds to wait between characters + /// in the spin. Defaults to the SpinnerStyle's Interval value. + /// + /// This is the maximum speed the spinner will rotate at. You still need to + /// call or to + /// advance/start animation. + public abstract int SpinDelay { get; } + + /// + /// Gets or sets whether spinner should go back and forth through the Sequence rather than + /// going to the end and starting again at the beginning. + /// + public abstract bool SpinBounce { get; } + + /// + /// Gets whether the current spinner style contains emoji or other special characters. + /// + public abstract bool HasSpecialCharacters { get; } + + /// + /// Gets or sets the frames used to animate the spinner. + /// + public abstract string [] Sequence { get; } + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + + // Placeholder when user has specified Delay and Sequence manually + public class Custom : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => Array.Empty (); + } + public class Dots : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "⠋", + "⠙", + "⠹", + "⠸", + "⠼", + "⠴", + "⠦", + "⠧", + "⠇", + "⠏", + }; + } + public class Dots2 : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "⣾", + "⣽", + "⣻", + "⢿", + "⡿", + "⣟", + "⣯", + "⣷", + }; + } + public class Dots3 : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "⠋", + "⠙", + "⠚", + "⠞", + "⠖", + "⠦", + "⠴", + "⠲", + "⠳", + "⠓", + }; + } + public class Dots4 : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => true; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "⠄", + "⠆", + "⠇", + "⠋", + "⠙", + "⠸", + "⠰", + "⠠", + }; + } + public class Dots5 : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "⠋", + "⠙", + "⠚", + "⠒", + "⠂", + "⠂", + "⠒", + "⠲", + "⠴", + "⠦", + "⠖", + "⠒", + "⠐", + "⠐", + "⠒", + "⠓", + "⠋", + }; + } + public class Dots6 : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => true; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "⠁", + "⠁", + "⠉", + "⠙", + "⠚", + "⠒", + "⠂", + "⠂", + "⠒", + "⠲", + "⠴", + "⠤", + "⠄", + "⠄", + }; + } + public class Dots7 : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => true; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "⠈", + "⠈", + "⠉", + "⠋", + "⠓", + "⠒", + "⠐", + "⠐", + "⠒", + "⠖", + "⠦", + "⠤", + "⠠", + "⠠", + }; + } + public class Dots8 : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "⠁", + "⠁", + "⠉", + "⠙", + "⠚", + "⠒", + "⠂", + "⠂", + "⠒", + "⠲", + "⠴", + "⠤", + "⠄", + "⠄", + "⠤", + "⠠", + "⠠", + "⠤", + "⠦", + "⠖", + "⠒", + "⠐", + "⠐", + "⠒", + "⠓", + "⠋", + "⠉", + "⠈", + "⠈", + }; + } + public class Dots9 : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "⢹", + "⢺", + "⢼", + "⣸", + "⣇", + "⡧", + "⡗", + "⡏", + }; + } + public class Dots10 : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "⢄", + "⢂", + "⢁", + "⡁", + "⡈", + "⡐", + "⡠", + }; + } + public class Dots11 : SpinnerStyle { + public override int SpinDelay => 100; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "⠁", + "⠂", + "⠄", + "⡀", + "⢀", + "⠠", + "⠐", + "⠈", + }; + } + public class Dots12 : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "⢀⠀", + "⡀⠀", + "⠄⠀", + "⢂⠀", + "⡂⠀", + "⠅⠀", + "⢃⠀", + "⡃⠀", + "⠍⠀", + "⢋⠀", + "⡋⠀", + "⠍⠁", + "⢋⠁", + "⡋⠁", + "⠍⠉", + "⠋⠉", + "⠋⠉", + "⠉⠙", + "⠉⠙", + "⠉⠩", + "⠈⢙", + "⠈⡙", + "⢈⠩", + "⡀⢙", + "⠄⡙", + "⢂⠩", + "⡂⢘", + "⠅⡘", + "⢃⠨", + "⡃⢐", + "⠍⡐", + "⢋⠠", + "⡋⢀", + "⠍⡁", + "⢋⠁", + "⡋⠁", + "⠍⠉", + "⠋⠉", + "⠋⠉", + "⠉⠙", + "⠉⠙", + "⠉⠩", + "⠈⢙", + "⠈⡙", + "⠈⠩", + "⠀⢙", + "⠀⡙", + "⠀⠩", + "⠀⢘", + "⠀⡘", + "⠀⠨", + "⠀⢐", + "⠀⡐", + "⠀⠠", + "⠀⢀", + "⠀⡀", + }; + } + public class Dots8Bit : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "⠀", + "⠁", + "⠂", + "⠃", + "⠄", + "⠅", + "⠆", + "⠇", + "⡀", + "⡁", + "⡂", + "⡃", + "⡄", + "⡅", + "⡆", + "⡇", + "⠈", + "⠉", + "⠊", + "⠋", + "⠌", + "⠍", + "⠎", + "⠏", + "⡈", + "⡉", + "⡊", + "⡋", + "⡌", + "⡍", + "⡎", + "⡏", + "⠐", + "⠑", + "⠒", + "⠓", + "⠔", + "⠕", + "⠖", + "⠗", + "⡐", + "⡑", + "⡒", + "⡓", + "⡔", + "⡕", + "⡖", + "⡗", + "⠘", + "⠙", + "⠚", + "⠛", + "⠜", + "⠝", + "⠞", + "⠟", + "⡘", + "⡙", + "⡚", + "⡛", + "⡜", + "⡝", + "⡞", + "⡟", + "⠠", + "⠡", + "⠢", + "⠣", + "⠤", + "⠥", + "⠦", + "⠧", + "⡠", + "⡡", + "⡢", + "⡣", + "⡤", + "⡥", + "⡦", + "⡧", + "⠨", + "⠩", + "⠪", + "⠫", + "⠬", + "⠭", + "⠮", + "⠯", + "⡨", + "⡩", + "⡪", + "⡫", + "⡬", + "⡭", + "⡮", + "⡯", + "⠰", + "⠱", + "⠲", + "⠳", + "⠴", + "⠵", + "⠶", + "⠷", + "⡰", + "⡱", + "⡲", + "⡳", + "⡴", + "⡵", + "⡶", + "⡷", + "⠸", + "⠹", + "⠺", + "⠻", + "⠼", + "⠽", + "⠾", + "⠿", + "⡸", + "⡹", + "⡺", + "⡻", + "⡼", + "⡽", + "⡾", + "⡿", + "⢀", + "⢁", + "⢂", + "⢃", + "⢄", + "⢅", + "⢆", + "⢇", + "⣀", + "⣁", + "⣂", + "⣃", + "⣄", + "⣅", + "⣆", + "⣇", + "⢈", + "⢉", + "⢊", + "⢋", + "⢌", + "⢍", + "⢎", + "⢏", + "⣈", + "⣉", + "⣊", + "⣋", + "⣌", + "⣍", + "⣎", + "⣏", + "⢐", + "⢑", + "⢒", + "⢓", + "⢔", + "⢕", + "⢖", + "⢗", + "⣐", + "⣑", + "⣒", + "⣓", + "⣔", + "⣕", + "⣖", + "⣗", + "⢘", + "⢙", + "⢚", + "⢛", + "⢜", + "⢝", + "⢞", + "⢟", + "⣘", + "⣙", + "⣚", + "⣛", + "⣜", + "⣝", + "⣞", + "⣟", + "⢠", + "⢡", + "⢢", + "⢣", + "⢤", + "⢥", + "⢦", + "⢧", + "⣠", + "⣡", + "⣢", + "⣣", + "⣤", + "⣥", + "⣦", + "⣧", + "⢨", + "⢩", + "⢪", + "⢫", + "⢬", + "⢭", + "⢮", + "⢯", + "⣨", + "⣩", + "⣪", + "⣫", + "⣬", + "⣭", + "⣮", + "⣯", + "⢰", + "⢱", + "⢲", + "⢳", + "⢴", + "⢵", + "⢶", + "⢷", + "⣰", + "⣱", + "⣲", + "⣳", + "⣴", + "⣵", + "⣶", + "⣷", + "⢸", + "⢹", + "⢺", + "⢻", + "⢼", + "⢽", + "⢾", + "⢿", + "⣸", + "⣹", + "⣺", + "⣻", + "⣼", + "⣽", + "⣾", + "⣿", + }; + } + public class Line : SpinnerStyle { + public override int SpinDelay => 130; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "-", + @"\", + "|", + "/", + }; + } + public class Line2 : SpinnerStyle { + public override int SpinDelay => 100; + public override bool SpinBounce => true; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "⠂", + "-", + "–", + "—", + }; + } + public class Pipe : SpinnerStyle { + public override int SpinDelay => 100; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "┤", + "┘", + "┴", + "└", + "├", + "┌", + "┬", + "┐", + }; + } + public class SimpleDots : SpinnerStyle { + public override int SpinDelay => 400; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + ". ", + ".. ", + "...", + " ", + }; + } + public class SimpleDotsScrolling : SpinnerStyle { + public override int SpinDelay => 200; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + ". ", + ".. ", + "...", + " ..", + " .", + " ", + }; + } + public class Star : SpinnerStyle { + public override int SpinDelay => 70; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "✶", + "✸", + "✹", + "✺", + "✹", + "✷", + }; + } + public class Star2 : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "+", + "x", + "*", + }; + } + public class Flip : SpinnerStyle { + public override int SpinDelay => 70; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "_", + "_", + "_", + "-", + "`", + "`", + "'", + "´", + "-", + "_", + "_", + "_", + }; + } + public class Hamburger : SpinnerStyle { + public override int SpinDelay => 100; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "☱", + "☲", + "☴", + }; + } + public class GrowVertical : SpinnerStyle { + public override int SpinDelay => 120; + public override bool SpinBounce => true; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "▁", + "▃", + "▄", + "▅", + "▆", + "▇", + }; + } + public class GrowHorizontal : SpinnerStyle { + public override int SpinDelay => 120; + public override bool SpinBounce => true; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "▏", + "▎", + "▍", + "▌", + "▋", + "▊", + "▉", + }; + } + public class Balloon : SpinnerStyle { + public override int SpinDelay => 140; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + " ", + ".", + "o", + "O", + "@", + "*", + " ", + }; + } + public class Balloon2 : SpinnerStyle { + public override int SpinDelay => 120; + public override bool SpinBounce => true; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + ".", + ".", + "o", + "O", + "°", + }; + } + public class Noise : SpinnerStyle { + public override int SpinDelay => 100; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "▓", + "▒", + "░", + }; + } + public class Bounce : SpinnerStyle { + public override int SpinDelay => 120; + public override bool SpinBounce => true; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "⠁", + "⠂", + "⠄", + }; + } + public class BoxBounce : SpinnerStyle { + public override int SpinDelay => 120; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "▖", + "▘", + "▝", + "▗", + }; + } + public class BoxBounce2 : SpinnerStyle { + public override int SpinDelay => 100; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "▌", + "▀", + "▐", + "▄", + }; + } + public class Triangle : SpinnerStyle { + public override int SpinDelay => 50; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "◢", + "◣", + "◤", + "◥", + }; + } + public class Arc : SpinnerStyle { + public override int SpinDelay => 100; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "◜", + "◠", + "◝", + "◞", + "◡", + "◟", + }; + } + public class Circle : SpinnerStyle { + public override int SpinDelay => 120; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "◡", + "⊙", + "◠", + }; + } + public class SquareCorners : SpinnerStyle { + public override int SpinDelay => 180; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "◰", + "◳", + "◲", + "◱", + }; + } + public class CircleQuarters : SpinnerStyle { + public override int SpinDelay => 120; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "◴", + "◷", + "◶", + "◵", + }; + } + public class CircleHalves : SpinnerStyle { + public override int SpinDelay => 50; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "◐", + "◓", + "◑", + "◒", + }; + } + public class Squish : SpinnerStyle { + public override int SpinDelay => 100; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "╫", + "╪", + }; + } + public class Toggle : SpinnerStyle { + public override int SpinDelay => 250; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "⊶", + "⊷", + }; + } + public class Toggle2 : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "▫", + "▪", + }; + } + public class Toggle3 : SpinnerStyle { + public override int SpinDelay => 120; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "□", + "■", + }; + } + public class Toggle4 : SpinnerStyle { + public override int SpinDelay => 100; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "■", + "□", + "▪", + "▫", + }; + } + public class Toggle5 : SpinnerStyle { + public override int SpinDelay => 100; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "▮", + "▯", + }; + } + public class Toggle6 : SpinnerStyle { + public override int SpinDelay => 300; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "ဝ", + "၀", + }; + } + public class Toggle7 : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "⦾", + "⦿", + }; + } + public class Toggle8 : SpinnerStyle { + public override int SpinDelay => 100; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "◍", + "◌", + }; + } + public class Toggle9 : SpinnerStyle { + public override int SpinDelay => 100; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "◉", + "◎", + }; + } + public class Toggle10 : SpinnerStyle { + public override int SpinDelay => 100; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "㊂", + "㊀", + "㊁", + }; + } + public class Toggle11 : SpinnerStyle { + public override int SpinDelay => 50; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "⧇", + "⧆", + }; + } + public class Toggle12 : SpinnerStyle { + public override int SpinDelay => 120; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "☗", + "☖", + }; + } + public class Toggle13 : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "=", + "*", + "-", + }; + } + public class Arrow : SpinnerStyle { + public override int SpinDelay => 100; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "←", + "↖", + "↑", + "↗", + "→", + "↘", + "↓", + "↙", + }; + } + public class Arrow2 : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => true; + public override string [] Sequence => new string [] + { + "⬆️ ", + "↗️ ", + "➡️ ", + "↘️ ", + "⬇️ ", + "↙️ ", + "⬅️ ", + "↖️ ", + }; + } + public class Arrow3 : SpinnerStyle { + public override int SpinDelay => 120; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "▹▹▹▹▹", + "▸▹▹▹▹", + "▹▸▹▹▹", + "▹▹▸▹▹", + "▹▹▹▸▹", + "▹▹▹▹▸", + }; + } + public class BouncingBar : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => true; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "[ ]", + "[= ]", + "[== ]", + "[=== ]", + "[ ===]", + "[ ==]", + "[ =]", + "[ ]", + }; + } + public class BouncingBall : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => true; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "(● )", + "( ● )", + "( ● )", + "( ● )", + "( ● )", + "( ●)", + }; + } + public class Smiley : SpinnerStyle { + public override int SpinDelay => 200; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => true; + public override string [] Sequence => new string [] + { + "😄 ", + "😝 ", + }; + } + public class Monkey : SpinnerStyle { + public override int SpinDelay => 300; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => true; + public override string [] Sequence => new string [] + { + "🙈 ", + "🙈 ", + "🙉 ", + "🙊 ", + }; + } + public class Hearts : SpinnerStyle { + public override int SpinDelay => 100; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => true; + public override string [] Sequence => new string [] + { + "💛 ", + "💙 ", + "💜 ", + "💚 ", + "❤️ ", + }; + } + public class Clock : SpinnerStyle { + public override int SpinDelay => 100; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => true; + public override string [] Sequence => new string [] + { + "🕛 ", + "🕐 ", + "🕑 ", + "🕒 ", + "🕓 ", + "🕔 ", + "🕕 ", + "🕖 ", + "🕗 ", + "🕘 ", + "🕙 ", + "🕚 ", + }; + } + public class Earth : SpinnerStyle { + public override int SpinDelay => 180; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => true; + public override string [] Sequence => new string [] + { + "🌍 ", + "🌎 ", + "🌏 ", + }; + } + public class Material : SpinnerStyle { + public override int SpinDelay => 17; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "███▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "████▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "███████▁▁▁▁▁▁▁▁▁▁▁▁▁", + "████████▁▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "██████████▁▁▁▁▁▁▁▁▁▁", + "███████████▁▁▁▁▁▁▁▁▁", + "█████████████▁▁▁▁▁▁▁", + "██████████████▁▁▁▁▁▁", + "██████████████▁▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁▁██████████████▁▁▁▁", + "▁▁▁██████████████▁▁▁", + "▁▁▁▁█████████████▁▁▁", + "▁▁▁▁██████████████▁▁", + "▁▁▁▁██████████████▁▁", + "▁▁▁▁▁██████████████▁", + "▁▁▁▁▁██████████████▁", + "▁▁▁▁▁██████████████▁", + "▁▁▁▁▁▁██████████████", + "▁▁▁▁▁▁██████████████", + "▁▁▁▁▁▁▁█████████████", + "▁▁▁▁▁▁▁█████████████", + "▁▁▁▁▁▁▁▁████████████", + "▁▁▁▁▁▁▁▁████████████", + "▁▁▁▁▁▁▁▁▁███████████", + "▁▁▁▁▁▁▁▁▁███████████", + "▁▁▁▁▁▁▁▁▁▁██████████", + "▁▁▁▁▁▁▁▁▁▁██████████", + "▁▁▁▁▁▁▁▁▁▁▁▁████████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁███████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁██████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████", + "█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████", + "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "███▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "████▁▁▁▁▁▁▁▁▁▁▁▁▁▁██", + "█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "██████▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "████████▁▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "███████████▁▁▁▁▁▁▁▁▁", + "████████████▁▁▁▁▁▁▁▁", + "████████████▁▁▁▁▁▁▁▁", + "██████████████▁▁▁▁▁▁", + "██████████████▁▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁▁▁█████████████▁▁▁▁", + "▁▁▁▁▁████████████▁▁▁", + "▁▁▁▁▁████████████▁▁▁", + "▁▁▁▁▁▁███████████▁▁▁", + "▁▁▁▁▁▁▁▁█████████▁▁▁", + "▁▁▁▁▁▁▁▁█████████▁▁▁", + "▁▁▁▁▁▁▁▁▁█████████▁▁", + "▁▁▁▁▁▁▁▁▁█████████▁▁", + "▁▁▁▁▁▁▁▁▁▁█████████▁", + "▁▁▁▁▁▁▁▁▁▁▁████████▁", + "▁▁▁▁▁▁▁▁▁▁▁████████▁", + "▁▁▁▁▁▁▁▁▁▁▁▁███████▁", + "▁▁▁▁▁▁▁▁▁▁▁▁███████▁", + "▁▁▁▁▁▁▁▁▁▁▁▁▁███████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁███████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + }; + } + public class Moon : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => true; + public override string [] Sequence => new string [] + { + "🌑 ", + "🌒 ", + "🌓 ", + "🌔 ", + "🌕 ", + "🌖 ", + "🌗 ", + "🌘 ", + }; + } + public class Runner : SpinnerStyle { + public override int SpinDelay => 140; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => true; + public override string [] Sequence => new string [] + { + "🚶 ", + "🏃 ", + }; + } + public class Pong : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => true; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "▐⠂ ▌", + "▐⠈ ▌", + "▐ ⠂ ▌", + "▐ ⠠ ▌", + "▐ ⡀ ▌", + "▐ ⠠ ▌", + "▐ ⠂ ▌", + "▐ ⠈ ▌", + "▐ ⠂ ▌", + "▐ ⠠ ▌", + "▐ ⡀ ▌", + "▐ ⠠ ▌", + "▐ ⠂ ▌", + "▐ ⠈ ▌", + "▐ ⠂▌", + "▐ ⠠▌", + "▐ ⡀▌", + "▐ ⠠ ▌", + "▐ ⠂ ▌", + "▐ ⠈ ▌", + "▐ ⠂ ▌", + "▐ ⠠ ▌", + "▐ ⡀ ▌", + "▐ ⠠ ▌", + "▐ ⠂ ▌", + "▐ ⠈ ▌", + "▐ ⠂ ▌", + "▐ ⠠ ▌", + "▐ ⡀ ▌", + "▐⠠ ▌", + }; + } + public class Shark : SpinnerStyle { + public override int SpinDelay => 120; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + @"▐|\____________▌", + @"▐_|\___________▌", + @"▐__|\__________▌", + @"▐___|\_________▌", + @"▐____|\________▌", + @"▐_____|\_______▌", + @"▐______|\______▌", + @"▐_______|\_____▌", + @"▐________|\____▌", + @"▐_________|\___▌", + @"▐__________|\__▌", + @"▐___________|\_▌", + @"▐____________|\▌", + "▐____________/|▌", + "▐___________/|_▌", + "▐__________/|__▌", + "▐_________/|___▌", + "▐________/|____▌", + "▐_______/|_____▌", + "▐______/|______▌", + "▐_____/|_______▌", + "▐____/|________▌", + "▐___/|_________▌", + "▐__/|__________▌", + "▐_/|___________▌", + "▐/|____________▌", + }; + } + public class Dqpb : SpinnerStyle { + public override int SpinDelay => 100; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "d", + "q", + "p", + "b", + }; + } + public class Weather : SpinnerStyle { + public override int SpinDelay => 100; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => true; + public override string [] Sequence => new string [] + { + "☀️ ", + "☀️ ", + "☀️ ", + "🌤 ", + "⛅️ ", + "🌥 ", + "☁️ ", + "🌧 ", + "🌨 ", + "🌧 ", + "🌨 ", + "🌧 ", + "🌨 ", + "⛈ ", + "🌨 ", + "🌧 ", + "🌨 ", + "☁️ ", + "🌥 ", + "⛅️ ", + "🌤 ", + "☀️ ", + "☀️ ", + }; + } + public class Christmas : SpinnerStyle { + public override int SpinDelay => 400; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => true; + public override string [] Sequence => new string [] + { + "🌲", + "🎄", + }; + } + public class Grenade : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => true; + public override string [] Sequence => new string [] + { + "، ", + "′ ", + " ´ ", + " ‾ ", + " ⸌", + " ⸊", + " |", + " ⁎", + " ⁕", + " ෴ ", + " ⁓", + " ", + " ", + " ", + }; + } + public class Points : SpinnerStyle { + public override int SpinDelay => 125; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "∙∙∙", + "●∙∙", + "∙●∙", + "∙∙●", + "∙∙∙", + }; + } + public class Layer : SpinnerStyle { + public override int SpinDelay => 150; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "-", + "=", + "≡", + }; + } + public class BetaWave : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "ρββββββ", + "βρβββββ", + "ββρββββ", + "βββρβββ", + "ββββρββ", + "βββββρβ", + "ββββββρ", + }; + } + public class FingerDance : SpinnerStyle { + public override int SpinDelay => 160; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => true; + public override string [] Sequence => new string [] + { + "🤘 ", + "🤟 ", + "🖖 ", + "✋ ", + "🤚 ", + "👆 " + }; + } + public class FistBump : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => true; + public override string [] Sequence => new string [] + { + "🤜\u3000\u3000\u3000\u3000🤛 ", + "🤜\u3000\u3000\u3000\u3000🤛 ", + "🤜\u3000\u3000\u3000\u3000🤛 ", + "\u3000🤜\u3000\u3000🤛\u3000 ", + "\u3000\u3000🤜🤛\u3000\u3000 ", + "\u3000🤜✨🤛\u3000\u3000 ", + "🤜\u3000✨\u3000🤛\u3000 " + }; + } + public class SoccerHeader : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => true; + public override bool HasSpecialCharacters => true; + public override string [] Sequence => new string [] + { + " 🧑⚽️ 🧑 ", + "🧑 ⚽️ 🧑 ", + "🧑 ⚽️ 🧑 ", + "🧑 ⚽️ 🧑 ", + "🧑 ⚽️ 🧑 ", + "🧑 ⚽️ 🧑 ", + "🧑 ⚽️🧑 ", + }; + } + public class MindBlown : SpinnerStyle { + public override int SpinDelay => 160; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => true; + public override string [] Sequence => new string [] + { + "😐 ", + "😐 ", + "😮 ", + "😮 ", + "😦 ", + "😦 ", + "😧 ", + "😧 ", + "🤯 ", + "💥 ", + "✨ ", + "\u3000 ", + "\u3000 ", + "\u3000 " + }; + } + public class Speaker : SpinnerStyle { + public override int SpinDelay => 160; + public override bool SpinBounce => true; + public override bool HasSpecialCharacters => true; + public override string [] Sequence => new string [] + { + "🔈 ", + "🔉 ", + "🔊 ", + }; + } + public class OrangePulse : SpinnerStyle { + public override int SpinDelay => 100; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => true; + public override string [] Sequence => new string [] + { + "🔸 ", + "🔶 ", + "🟠 ", + "🟠 ", + "🔶 " + }; + } + public class BluePulse : SpinnerStyle { + public override int SpinDelay => 100; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => true; + public override string [] Sequence => new string [] + { + "🔹 ", + "🔷 ", + "🔵 ", + "🔵 ", + "🔷 " + }; + } + public class OrangeBluePulse : SpinnerStyle { + public override int SpinDelay => 100; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => true; + public override string [] Sequence => new string [] + { + "🔸 ", + "🔶 ", + "🟠 ", + "🟠 ", + "🔶 ", + "🔹 ", + "🔷 ", + "🔵 ", + "🔵 ", + "🔷 " + }; + } + public class TimeTravelClock : SpinnerStyle { + public override int SpinDelay => 100; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => true; + public override string [] Sequence => new string [] + { + "🕛 ", + "🕚 ", + "🕙 ", + "🕘 ", + "🕗 ", + "🕖 ", + "🕕 ", + "🕔 ", + "🕓 ", + "🕒 ", + "🕑 ", + "🕐 " + }; + } + public class Aesthetic : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "▰▱▱▱▱▱▱", + "▰▰▱▱▱▱▱", + "▰▰▰▱▱▱▱", + "▰▰▰▰▱▱▱", + "▰▰▰▰▰▱▱", + "▰▰▰▰▰▰▱", + "▰▰▰▰▰▰▰", + "▰▱▱▱▱▱▱", + }; + } + public class Aesthetic2 : SpinnerStyle { + public override int SpinDelay => DEFAULT_DELAY; + public override bool SpinBounce => DEFAULT_BOUNCE; + public override bool HasSpecialCharacters => DEFAULT_SPECIAL; + public override string [] Sequence => new string [] + { + "▰▱▱▱▱▱▱", + "▰▰▱▱▱▱▱", + "▰▰▰▱▱▱▱", + "▰▰▰▰▱▱▱", + "▰▰▰▰▰▱▱", + "▰▰▰▰▰▰▱", + "▰▰▰▰▰▰▰", + "▱▰▰▰▰▰▰", + "▱▱▰▰▰▰▰", + "▱▱▱▰▰▰▰", + "▱▱▱▱▰▰▰", + "▱▱▱▱▱▰▰", + "▱▱▱▱▱▱▰", + "▱▱▱▱▱▱▱", + }; + } +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member + } +} \ No newline at end of file diff --git a/Terminal.Gui/Views/SpinnerView/SpinnerView.cs b/Terminal.Gui/Views/SpinnerView/SpinnerView.cs new file mode 100644 index 000000000..231b1eb1d --- /dev/null +++ b/Terminal.Gui/Views/SpinnerView/SpinnerView.cs @@ -0,0 +1,219 @@ +//------------------------------------------------------------------------------ +// Windows Terminal supports Unicode and Emoji characters, but by default +// conhost shells (e.g., PowerShell and cmd.exe) do not. See +// . +//------------------------------------------------------------------------------ + +using System; + +namespace Terminal.Gui { + /// + /// A which displays (by default) a spinning line character. + /// + /// + /// By default animation only occurs when you call . + /// Use to make the automate calls to . + /// + public class SpinnerView : View { + private const int DEFAULT_DELAY = 130; + private static readonly SpinnerStyle DEFAULT_STYLE = new SpinnerStyle.Line (); + + private SpinnerStyle _style = DEFAULT_STYLE; + private int _delay = DEFAULT_STYLE.SpinDelay; + private bool _bounce = DEFAULT_STYLE.SpinBounce; + private string [] _sequence = DEFAULT_STYLE.Sequence; + private bool _bounceReverse = false; + private int _currentIdx = 0; + private DateTime _lastRender = DateTime.MinValue; + private object _timeout; + + /// + /// Gets or sets the Style used to animate the spinner. + /// + public SpinnerStyle Style { get => _style; set => SetStyle (value); } + + /// + /// Gets or sets the animation frames used to animate the spinner. + /// + public string [] Sequence { get => _sequence; set => SetSequence (value); } + + /// + /// Gets or sets the number of milliseconds to wait between characters + /// in the animation. + /// + /// This is the maximum speed the spinner will rotate at. You still need to + /// call or to + /// advance/start animation. + public int SpinDelay { get => _delay; set => SetDelay (value); } + + /// + /// Gets or sets whether spinner should go back and forth through the frames rather than + /// going to the end and starting again at the beginning. + /// + public bool SpinBounce { get => _bounce; set => SetBounce (value); } + + /// + /// Gets or sets whether spinner should go through the frames in reverse order. + /// If SpinBounce is true, this sets the starting order. + /// + public bool SpinReverse { get; set; } = false; + + /// + /// Gets whether the current spinner style contains emoji or other special characters. + /// Does not check Custom sequences. + /// + public bool HasSpecialCharacters { get => _style.HasSpecialCharacters; } + + /// + /// Gets whether the current spinner style contains only ASCII characters. Also checks Custom sequences. + /// + public bool IsAsciiOnly { get => GetIsAsciiOnly (); } + + /// + /// Creates a new instance of the class. + /// + public SpinnerView () + { + Width = 1; + Height = 1; + _delay = DEFAULT_DELAY; + _bounce = false; + SpinReverse = false; + SetStyle (DEFAULT_STYLE); + } + + private void SetStyle (SpinnerStyle style) + { + if (style is not null) { + _style = style; + _sequence = style.Sequence; + _delay = style.SpinDelay; + _bounce = style.SpinBounce; + Width = GetSpinnerWidth (); + } + } + + private void SetSequence (string [] frames) + { + if (frames is not null && frames.Length > 0) { + _style = new SpinnerStyle.Custom (); + _sequence = frames; + Width = GetSpinnerWidth (); + } + } + + private void SetDelay (int delay) + { + if (delay > -1) { + _delay = delay; + } + } + + private void SetBounce (bool bounce) + { + _bounce = bounce; + } + + private int GetSpinnerWidth () + { + int max = 0; + if (_sequence is not null && _sequence.Length > 0) { + foreach (string frame in _sequence) { + if (frame.Length > max) { + max = frame.Length; + } + } + } + return max; + } + + private bool GetIsAsciiOnly () + { + if (HasSpecialCharacters) { + return false; + } + if (_sequence is not null && _sequence.Length > 0) { + foreach (string frame in _sequence) { + foreach (char c in frame) { + if (!char.IsAscii (c)) { + return false; + } + } + } + return true; + } + return true; + } + + /// + public override void Redraw (Rect bounds) + { + if (DateTime.Now - _lastRender > TimeSpan.FromMilliseconds (SpinDelay)) { + //_currentIdx = (_currentIdx + 1) % Sequence.Length; + if (Sequence is not null && Sequence.Length > 1) { + int d = 1; + if ((_bounceReverse && !SpinReverse) || (!_bounceReverse && SpinReverse)) { + d = -1; + } + _currentIdx += d; + + if (_currentIdx >= Sequence.Length) { + if (SpinBounce) { + if (SpinReverse) { + _bounceReverse = false; + } else { + _bounceReverse = true; + } + _currentIdx = Sequence.Length - 1; + } else { + _currentIdx = 0; + } + } + if (_currentIdx < 0) { + if (SpinBounce) { + if (SpinReverse) { + _bounceReverse = true; + } else { + _bounceReverse = false; + } + _currentIdx = 1; + } else { + _currentIdx = Sequence.Length - 1; + } + } + Text = "" + Sequence [_currentIdx]; //.EnumerateRunes; + } + _lastRender = DateTime.Now; + } + + base.Redraw (bounds); + } + + /// + /// Automates spinning + /// + public void AutoSpin () + { + if (_timeout != null) { + return; + } + + _timeout = Application.MainLoop.AddTimeout ( + TimeSpan.FromMilliseconds (SpinDelay), (m) => { + Application.MainLoop.Invoke (this.SetNeedsDisplay); + return true; + }); + } + + /// + protected override void Dispose (bool disposing) + { + if (_timeout != null) { + Application.MainLoop.RemoveTimeout (_timeout); + _timeout = null; + } + + base.Dispose (disposing); + } + } +} \ No newline at end of file diff --git a/UICatalog/Scenarios/Progress.cs b/UICatalog/Scenarios/Progress.cs index f94512aa4..b33d8b0fe 100644 --- a/UICatalog/Scenarios/Progress.cs +++ b/UICatalog/Scenarios/Progress.cs @@ -3,7 +3,6 @@ using System; using System.Threading; using Terminal.Gui; using System.Linq; -using System.Runtime.CompilerServices; namespace UICatalog.Scenarios { // @@ -11,7 +10,7 @@ namespace UICatalog.Scenarios { // [ScenarioMetadata (Name: "Progress", Description: "Shows off ProgressBar and Threading.")] [ScenarioCategory ("Controls")] - [ScenarioCategory ("Threading"), ScenarioCategory ("ProgressBar")] + [ScenarioCategory ("Threading"), ScenarioCategory ("Progress")] public class Progress : Scenario { class ProgressDemo : FrameView { @@ -79,25 +78,29 @@ namespace UICatalog.Scenarios { ActivityProgressBar = new ProgressBar () { X = Pos.Right (LeftFrame) + 1, Y = Pos.Bottom (startButton) + 1, - Width = Dim.Fill (), + Width = Dim.Fill () - 1, Height = 1, Fraction = 0.25F, ColorScheme = Colors.Error }; Add (ActivityProgressBar); - Spinner = new SpinnerView { - X = Pos.Right (ActivityProgressBar), + Spinner = new SpinnerView () { + Style = new SpinnerStyle.Dots2 (), + SpinReverse = true, Y = ActivityProgressBar.Y, - Visible = false, - + Visible = false }; + ActivityProgressBar.Width = Dim.Fill () - Spinner.Width; + Spinner.X = Pos.Right (ActivityProgressBar); + + Add (Spinner); PulseProgressBar = new ProgressBar () { X = Pos.Right (LeftFrame) + 1, Y = Pos.Bottom (ActivityProgressBar) + 1, - Width = Dim.Fill (), + Width = Dim.Fill () - Spinner.Width, Height = 1, ColorScheme = Colors.Error }; @@ -122,7 +125,7 @@ namespace UICatalog.Scenarios { StartBtnClick?.Invoke (); Application.MainLoop.Invoke(()=>{ Spinner.Visible = true; - ActivityProgressBar.Width = Dim.Fill(1); + ActivityProgressBar.Width = Dim.Fill () - Spinner.Width; this.LayoutSubviews(); }); } @@ -134,13 +137,14 @@ namespace UICatalog.Scenarios { Application.MainLoop.Invoke(()=>{ Spinner.Visible = false; - ActivityProgressBar.Width = Dim.Fill(); + ActivityProgressBar.Width = Dim.Fill () - Spinner.Width; this.LayoutSubviews(); }); } internal void Pulse () { + Spinner.Visible = true; if (PulseBtnClick != null) { PulseBtnClick?.Invoke (); diff --git a/UICatalog/Scenarios/ProgressBarStyles.cs b/UICatalog/Scenarios/ProgressBarStyles.cs index bc8ba33e0..c64c6dfdb 100644 --- a/UICatalog/Scenarios/ProgressBarStyles.cs +++ b/UICatalog/Scenarios/ProgressBarStyles.cs @@ -6,7 +6,7 @@ using Terminal.Gui; namespace UICatalog.Scenarios { [ScenarioMetadata (Name: "ProgressBar Styles", Description: "Shows the ProgressBar Styles.")] [ScenarioCategory ("Controls")] - [ScenarioCategory ("ProgressBar")] + [ScenarioCategory ("Progress")] [ScenarioCategory ("Threading")] public class ProgressBarStyles : Scenario { diff --git a/UICatalog/Scenarios/SpinnerStyles.cs b/UICatalog/Scenarios/SpinnerStyles.cs new file mode 100644 index 000000000..5e07b9471 --- /dev/null +++ b/UICatalog/Scenarios/SpinnerStyles.cs @@ -0,0 +1,183 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Terminal.Gui; + +namespace UICatalog.Scenarios { + [ScenarioMetadata (Name: "SpinnerView Styles", Description: "Shows the SpinnerView Styles.")] + [ScenarioCategory ("Controls")] + [ScenarioCategory ("Progress")] + + public class SpinnerViewStyles : Scenario { + class Property { + public string Name { get; set; } + } + + public override void Setup () + { + const int DEFAULT_DELAY = 130; + const string DEFAULT_CUSTOM = @"-\|/"; + var styleDict = new Dictionary> (); + int i = 0; + foreach (var style in typeof (SpinnerStyle).GetNestedTypes ()) { + styleDict.Add (i, new KeyValuePair (style.Name, style)); + i++; + } + + var preview = new View () { + X = Pos.Center (), + Y = 0, + Width = 22, + Height = 3, + //Title = "Preview", + BorderStyle = LineStyle.Single + }; + Win.Add (preview); + + var spinner = new SpinnerView () { + X = Pos.Center (), + Y = 0 + }; + preview.Add (spinner); + spinner.AutoSpin (); + + var ckbAscii = new CheckBox ("Ascii Only", false) { + X = Pos.Center () - 7, + Y = Pos.Bottom (preview), + Enabled = false, + Checked = true + }; + Win.Add (ckbAscii); + + var ckbNoSpecial = new CheckBox ("No Special", false) { + X = Pos.Center () + 7, + Y = Pos.Bottom (preview), + Enabled = false, + Checked = true + }; + Win.Add (ckbNoSpecial); + + var ckbReverse = new CheckBox ("Reverse", false) { + X = Pos.Center () - 22, + Y = Pos.Bottom (preview) + 1, + Checked = false + }; + Win.Add (ckbReverse); + + var ckbBounce = new CheckBox ("Bounce", false) { + X = Pos.Right (ckbReverse) + 2, + Y = Pos.Bottom (preview) + 1, + Checked = false + }; + Win.Add (ckbBounce); + + var delayLabel = new Label ("Delay:") { + X = Pos.Right (ckbBounce) + 2, + Y = Pos.Bottom (preview) + 1 + }; + Win.Add (delayLabel); + var delayField = new TextField (DEFAULT_DELAY.ToString ()) { + X = Pos.Right (delayLabel), + Y = Pos.Bottom (preview) + 1, + Width = 5 + }; + Win.Add (delayField); + delayField.TextChanged += (s, e) => { + if (ushort.TryParse (delayField.Text.ToString (), out var i)) + spinner.SpinDelay = i; + }; + + var customLabel = new Label ("Custom:") { + X = Pos.Right (delayField) + 2, + Y = Pos.Bottom (preview) + 1 + }; + Win.Add (customLabel); + var customField = new TextField (DEFAULT_CUSTOM) { + X = Pos.Right (customLabel), + Y = Pos.Bottom (preview) + 1, + Width = 12 + }; + Win.Add (customField); + + var styleArray = styleDict.Select (e => NStack.ustring.Make (e.Value.Key.ToString ())).ToArray (); + if (styleArray.Length < 1) + return; + + var styles = new ListView () { + X = Pos.Center (), + Y = Pos.Bottom (preview) + 2, + Height = Dim.Fill (), + Width = Dim.Fill (1) + }; + styles.SetSource (styleArray); + styles.SelectedItem = 0; // SpinnerStyle.Custom; + Win.Add (styles); + SetCustom (); + + customField.TextChanged += (s, e) => { + if (customField.Text.Length > 0) { + if (styles.SelectedItem != 0) + styles.SelectedItem = 0; // SpinnerStyle.Custom + SetCustom (); + } + }; + + styles.SelectedItemChanged += (s, e) => { + if (e.Item == 0) { // SpinnerStyle.Custom + if (customField.Text.Length < 1) + customField.Text = DEFAULT_CUSTOM; + if (delayField.Text.Length < 1) + delayField.Text = DEFAULT_DELAY.ToString (); + SetCustom (); + } else { + spinner.Visible = true; + spinner.Style = (SpinnerStyle)Activator.CreateInstance(styleDict [e.Item].Value); + delayField.Text = spinner.SpinDelay.ToString (); + ckbBounce.Checked = spinner.SpinBounce; + ckbNoSpecial.Checked = !spinner.HasSpecialCharacters; + ckbAscii.Checked = spinner.IsAsciiOnly; + ckbReverse.Checked = false; + } + }; + + ckbReverse.Toggled += (s, e) => { + spinner.SpinReverse = (bool)!e.OldValue; + }; + + ckbBounce.Toggled += (s, e) => { + spinner.SpinBounce = (bool)!e.OldValue; + }; + + Application.Top.Unloaded += Top_Unloaded; + + void SetCustom () + { + if (customField.Text.Length > 0) { + spinner.Visible = true; + if (ushort.TryParse (delayField.Text.ToString (), out var d)) + spinner.SpinDelay = d; + else { + delayField.Text = DEFAULT_DELAY.ToString (); + spinner.SpinDelay = DEFAULT_DELAY; + } + var str = new List (); + foreach (var c in customField.Text.ToString ().ToCharArray ()) { + str.Add (c.ToString ()); + } + spinner.Sequence = str.ToArray (); + } else { + spinner.Visible = false; + } + } + + void Top_Unloaded (object sender, EventArgs args) + { + if (spinner != null) { + spinner.Dispose (); + spinner = null; + } + Application.Top.Unloaded -= Top_Unloaded; + } + } + } +} \ No newline at end of file diff --git a/UnitTests/Views/SpinnerViewTests.cs b/UnitTests/Views/SpinnerViewTests.cs index 7260d1082..abb1b5ef9 100644 --- a/UnitTests/Views/SpinnerViewTests.cs +++ b/UnitTests/Views/SpinnerViewTests.cs @@ -42,19 +42,19 @@ namespace Terminal.Gui.ViewsTests { view.Redraw (view.Bounds); - var expected = "/"; + var expected = @"\"; TestHelpers.AssertDriverContentsWithFrameAre (expected, output); view.SetNeedsDisplay (); view.Redraw (view.Bounds); - expected = "/"; + expected = @"\"; TestHelpers.AssertDriverContentsWithFrameAre (expected, output); view.SetNeedsDisplay (); view.Redraw (view.Bounds); - expected = "/"; + expected = @"\"; TestHelpers.AssertDriverContentsWithFrameAre (expected, output); Task.Delay (400).Wait(); @@ -62,24 +62,24 @@ namespace Terminal.Gui.ViewsTests { view.SetNeedsDisplay (); view.Redraw (view.Bounds); - expected = "─"; + expected = "|"; TestHelpers.AssertDriverContentsWithFrameAre (expected, output); } [Fact, AutoInitShutdown] public void TestSpinnerView_NoThrottle () { var view = GetSpinnerView (); - view.SpinDelayInMilliseconds = 0; + view.SpinDelay = 0; view.Redraw (view.Bounds); - var expected = @"─"; + var expected = "|"; TestHelpers.AssertDriverContentsWithFrameAre (expected, output); view.SetNeedsDisplay (); view.Redraw (view.Bounds); - expected = @"\"; + expected = "/"; TestHelpers.AssertDriverContentsWithFrameAre (expected, output); }