TextEffectsScenario.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Threading;
  5. using Terminal.Gui;
  6. using Terminal.Gui.TextEffects;
  7. using static UICatalog.Scenario;
  8. using Color = Terminal.Gui.TextEffects.Color;
  9. using Animation = Terminal.Gui.TextEffects.Animation;
  10. namespace UICatalog.Scenarios;
  11. [ScenarioMetadata ("Text Effects", "Text Effects.")]
  12. [ScenarioCategory ("Colors")]
  13. public class TextEffectsScenario : Scenario
  14. {
  15. public override void Main ()
  16. {
  17. Application.Init ();
  18. var top = Application.Top;
  19. // Creates a window that occupies the entire terminal with a title.
  20. var window = new Window ()
  21. {
  22. X = 0,
  23. Y = 1, // Leaves one row for the toplevel menu
  24. // By using Dim.Fill(), it will automatically resize without manual intervention
  25. Width = Dim.Fill (),
  26. Height = Dim.Fill (),
  27. Title = "Text Effects Scenario"
  28. };
  29. // Create a large empty view.
  30. var emptyView = new TextEffectsExampleView ()
  31. {
  32. X = 0,
  33. Y = 0,
  34. Width = Dim.Fill (),
  35. Height = Dim.Fill (),
  36. };
  37. window.Add (emptyView);
  38. // Create a label in the center of the window.
  39. var label = new Label ()
  40. {
  41. X = Pos.Center (),
  42. Y = Pos.Center (),
  43. Width = 10,
  44. Height = 1,
  45. Text = "Hello"
  46. };
  47. window.Add (label);
  48. Application.Run (window);
  49. Application.Shutdown ();
  50. }
  51. }
  52. internal class TextEffectsExampleView : View
  53. {
  54. Ball? _ball;
  55. private bool resized;
  56. protected override void OnViewportChanged (DrawEventArgs e)
  57. {
  58. base.OnViewportChanged (e);
  59. resized = true;
  60. }
  61. public override void OnDrawContent (Rectangle viewport)
  62. {
  63. base.OnDrawContent (viewport);
  64. if (
  65. // First time
  66. (_ball == null && viewport.Width > 0 && viewport.Height > 0)
  67. || resized)
  68. {
  69. _ball = new Ball (this);
  70. _ball.Start ();
  71. resized = false;
  72. }
  73. DrawTopLineGradient (viewport);
  74. DrawRadialGradient (viewport);
  75. _ball?.Draw ();
  76. }
  77. private void DrawRadialGradient (Rectangle viewport)
  78. {
  79. // Define the colors of the gradient stops
  80. var stops = new List<Color>
  81. {
  82. Color.FromRgb(255, 0, 0), // Red
  83. Color.FromRgb(0, 255, 0), // Green
  84. Color.FromRgb(238, 130, 238) // Violet
  85. };
  86. // Define the number of steps between each color
  87. var steps = new List<int> { 10, 10 }; // 10 steps between Red -> Green, and Green -> Blue
  88. // Create the gradient
  89. var radialGradient = new Gradient (stops, steps, loop: false);
  90. // Define the size of the rectangle
  91. int maxRow = 20;
  92. int maxColumn = 40;
  93. // Build the coordinate-color mapping for a radial gradient
  94. var gradientMapping = radialGradient.BuildCoordinateColorMapping (maxRow, maxColumn, Gradient.Direction.Radial);
  95. // Print the gradient
  96. for (int row = 0; row <= maxRow; row++)
  97. {
  98. for (int col = 0; col <= maxColumn; col++)
  99. {
  100. var coord = new Coord (col, row);
  101. var color = gradientMapping [coord];
  102. SetColor (color);
  103. AddRune (col+2, row+3, new Rune ('█'));
  104. }
  105. }
  106. }
  107. private void DrawTopLineGradient (Rectangle viewport)
  108. {
  109. // Define the colors of the rainbow
  110. var stops = new List<Color>
  111. {
  112. Color.FromRgb(255, 0, 0), // Red
  113. Color.FromRgb(255, 165, 0), // Orange
  114. Color.FromRgb(255, 255, 0), // Yellow
  115. Color.FromRgb(0, 128, 0), // Green
  116. Color.FromRgb(0, 0, 255), // Blue
  117. Color.FromRgb(75, 0, 130), // Indigo
  118. Color.FromRgb(238, 130, 238) // Violet
  119. };
  120. // Define the number of steps between each color
  121. var steps = new List<int>
  122. {
  123. 20, // between Red and Orange
  124. 20, // between Orange and Yellow
  125. 20, // between Yellow and Green
  126. 20, // between Green and Blue
  127. 20, // between Blue and Indigo
  128. 20 // between Indigo and Violet
  129. };
  130. // Create the gradient
  131. var rainbowGradient = new Gradient (stops, steps, loop: true);
  132. for (int x = 0; x < viewport.Width; x++)
  133. {
  134. double fraction = (double)x / (viewport.Width - 1);
  135. Color color = rainbowGradient.GetColorAtFraction (fraction);
  136. SetColor (color);
  137. AddRune (x, 0, new Rune ('█'));
  138. }
  139. }
  140. private void SetColor (Color color)
  141. {
  142. // Assuming AddRune is a method you have for drawing at specific positions
  143. Application.Driver.SetAttribute (
  144. new Attribute (
  145. new Terminal.Gui.Color (color.R, color.G, color.B),
  146. new Terminal.Gui.Color (color.R, color.G, color.B)
  147. )); // Setting color based on RGB
  148. }
  149. public class Ball
  150. {
  151. public Animation Animation { get; private set; }
  152. public Scene BouncingScene { get; private set; }
  153. public View Viewport { get; private set; }
  154. public EffectCharacter Character { get; private set; }
  155. public Ball (View viewport)
  156. {
  157. Viewport = viewport;
  158. Character = new EffectCharacter (1, "O", 0, 0);
  159. Animation = Character.Animation;
  160. CreateBouncingScene ();
  161. CreateMotionPath ();
  162. }
  163. private void CreateBouncingScene ()
  164. {
  165. BouncingScene = Animation.NewScene (isLooping: true);
  166. int width = Viewport.Frame.Width;
  167. int height = Viewport.Frame.Height;
  168. double frequency = 4 * Math.PI / width; // Double the frequency
  169. for (int x = 0; x < width; x++)
  170. {
  171. int y = (int)((height) / 2 * (1 + Math.Sin (frequency * x))); // Decrease amplitude
  172. BouncingScene.AddFrame ("O", 1);
  173. }
  174. for (int x = width - 1; x >= 0; x--)
  175. {
  176. int y = (int)((height) / 2 * (1 + Math.Sin (frequency * x))); // Decrease amplitude
  177. BouncingScene.AddFrame ("O", 1);
  178. }
  179. }
  180. private void CreateMotionPath ()
  181. {
  182. int width = Viewport.Frame.Width;
  183. int height = Viewport.Frame.Height;
  184. double frequency = 4 * Math.PI / width; // Double the frequency
  185. var path = Character.Motion.CreatePath ("sineWavePath", speed: 1, loop: true);
  186. for (int x = 0; x < width; x++)
  187. {
  188. int y = (int)((height) / 2 * (1 + Math.Sin (frequency * x))); // Decrease amplitude
  189. path.AddWaypoint (new Waypoint ($"waypoint_{x}", new Coord (x, y)));
  190. }
  191. for (int x = width - 1; x >= 0; x--)
  192. {
  193. int y = (int)((height) / 2 * (1 + Math.Sin (frequency * x))); // Decrease amplitude
  194. path.AddWaypoint (new Waypoint ($"waypoint_{x}", new Coord (x, y)));
  195. }
  196. Character.Motion.ActivatePath (path);
  197. }
  198. public void Start ()
  199. {
  200. Animation.ActivateScene (BouncingScene);
  201. new Thread (() =>
  202. {
  203. while (true)
  204. {
  205. Thread.Sleep (10); // Adjust the speed of animation
  206. Character.Tick ();
  207. Application.Invoke (() => Viewport.SetNeedsDisplay ());
  208. }
  209. })
  210. { IsBackground = true }.Start ();
  211. }
  212. public void Draw ()
  213. {
  214. Driver.SetAttribute (Viewport.ColorScheme.Normal);
  215. Viewport.AddRune (Character.Motion.CurrentCoord.Column, Character.Motion.CurrentCoord.Row, new Rune ('O'));
  216. }
  217. }
  218. }