whirled_peas 0.4.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +1 -0
  4. data/CHANGELOG.md +37 -0
  5. data/README.md +529 -156
  6. data/Rakefile +9 -3
  7. data/bin/reset_cursor +11 -0
  8. data/bin/screen_test +68 -0
  9. data/examples/intro.rb +52 -0
  10. data/examples/scrolling.rb +54 -0
  11. data/lib/whirled_peas.rb +6 -12
  12. data/lib/whirled_peas/animator.rb +5 -0
  13. data/lib/whirled_peas/animator/debug_consumer.rb +17 -0
  14. data/lib/whirled_peas/animator/easing.rb +72 -0
  15. data/lib/whirled_peas/animator/frame.rb +5 -0
  16. data/lib/whirled_peas/animator/frameset.rb +33 -0
  17. data/lib/whirled_peas/animator/producer.rb +35 -0
  18. data/lib/whirled_peas/animator/renderer_consumer.rb +31 -0
  19. data/lib/whirled_peas/command.rb +5 -0
  20. data/lib/whirled_peas/command/base.rb +86 -0
  21. data/lib/whirled_peas/command/config_command.rb +44 -0
  22. data/lib/whirled_peas/command/debug.rb +21 -0
  23. data/lib/whirled_peas/command/fonts.rb +22 -0
  24. data/lib/whirled_peas/command/frame_command.rb +34 -0
  25. data/lib/whirled_peas/command/frames.rb +24 -0
  26. data/lib/whirled_peas/command/help.rb +38 -0
  27. data/lib/whirled_peas/command/play.rb +108 -0
  28. data/lib/whirled_peas/command/record.rb +57 -0
  29. data/lib/whirled_peas/command/still.rb +29 -0
  30. data/lib/whirled_peas/command_line.rb +23 -228
  31. data/lib/whirled_peas/config.rb +56 -6
  32. data/lib/whirled_peas/device.rb +5 -0
  33. data/lib/whirled_peas/device/null_device.rb +8 -0
  34. data/lib/whirled_peas/device/output_file.rb +19 -0
  35. data/lib/whirled_peas/device/screen.rb +26 -0
  36. data/lib/whirled_peas/errors.rb +2 -0
  37. data/lib/whirled_peas/graphics.rb +19 -0
  38. data/lib/whirled_peas/graphics/box_painter.rb +101 -0
  39. data/lib/whirled_peas/graphics/canvas.rb +118 -0
  40. data/lib/whirled_peas/graphics/composer.rb +80 -0
  41. data/lib/whirled_peas/graphics/container_coords.rb +72 -0
  42. data/lib/whirled_peas/graphics/container_dimensions.rb +93 -0
  43. data/lib/whirled_peas/graphics/container_painter.rb +363 -0
  44. data/lib/whirled_peas/graphics/debugger.rb +52 -0
  45. data/lib/whirled_peas/graphics/grid_painter.rb +69 -0
  46. data/lib/whirled_peas/graphics/mock_screen.rb +26 -0
  47. data/lib/whirled_peas/graphics/painter.rb +33 -0
  48. data/lib/whirled_peas/graphics/renderer.rb +32 -0
  49. data/lib/whirled_peas/graphics/text_dimensions.rb +15 -0
  50. data/lib/whirled_peas/graphics/text_painter.rb +40 -0
  51. data/lib/whirled_peas/settings.rb +5 -0
  52. data/lib/whirled_peas/settings/alignment.rb +24 -0
  53. data/lib/whirled_peas/settings/bg_color.rb +24 -0
  54. data/lib/whirled_peas/settings/border.rb +101 -0
  55. data/lib/whirled_peas/settings/box_settings.rb +8 -0
  56. data/lib/whirled_peas/settings/color.rb +68 -0
  57. data/lib/whirled_peas/settings/container_settings.rb +223 -0
  58. data/lib/whirled_peas/settings/debugger.rb +96 -0
  59. data/lib/whirled_peas/settings/display_flow.rb +27 -0
  60. data/lib/whirled_peas/settings/element_settings.rb +61 -0
  61. data/lib/whirled_peas/settings/grid_settings.rb +19 -0
  62. data/lib/whirled_peas/settings/margin.rb +8 -0
  63. data/lib/whirled_peas/settings/padding.rb +8 -0
  64. data/lib/whirled_peas/settings/position.rb +15 -0
  65. data/lib/whirled_peas/settings/scrollbar.rb +15 -0
  66. data/lib/whirled_peas/settings/sizing.rb +19 -0
  67. data/lib/whirled_peas/settings/spacing.rb +58 -0
  68. data/lib/whirled_peas/settings/text_color.rb +21 -0
  69. data/lib/whirled_peas/settings/text_settings.rb +15 -0
  70. data/lib/whirled_peas/settings/vert_alignment.rb +24 -0
  71. data/lib/whirled_peas/utils/ansi.rb +19 -56
  72. data/lib/whirled_peas/utils/file_handler.rb +57 -0
  73. data/lib/whirled_peas/utils/formatted_string.rb +64 -0
  74. data/lib/whirled_peas/utils/title_font.rb +1 -1
  75. data/lib/whirled_peas/version.rb +1 -1
  76. data/screen_test/elements/box.frame +1 -0
  77. data/screen_test/elements/box.rb +20 -0
  78. data/screen_test/elements/grid.frame +1 -0
  79. data/screen_test/elements/grid.rb +13 -0
  80. data/screen_test/elements/screen_overflow_x.frame +1 -0
  81. data/screen_test/elements/screen_overflow_x.rb +9 -0
  82. data/screen_test/elements/screen_overflow_y.frame +1 -0
  83. data/screen_test/elements/screen_overflow_y.rb +9 -0
  84. data/screen_test/elements/text.frame +1 -0
  85. data/screen_test/elements/text.rb +9 -0
  86. data/screen_test/elements/text_multiline.frame +1 -0
  87. data/screen_test/elements/text_multiline.rb +9 -0
  88. data/screen_test/settings/align/box_around.frame +1 -0
  89. data/screen_test/settings/align/box_around.rb +16 -0
  90. data/screen_test/settings/align/box_between.frame +1 -0
  91. data/screen_test/settings/align/box_between.rb +16 -0
  92. data/screen_test/settings/align/box_center.frame +1 -0
  93. data/screen_test/settings/align/box_center.rb +21 -0
  94. data/screen_test/settings/align/box_default.frame +1 -0
  95. data/screen_test/settings/align/box_default.rb +20 -0
  96. data/screen_test/settings/align/box_evenly.frame +1 -0
  97. data/screen_test/settings/align/box_evenly.rb +16 -0
  98. data/screen_test/settings/align/box_left.frame +1 -0
  99. data/screen_test/settings/align/box_left.rb +21 -0
  100. data/screen_test/settings/align/box_right.frame +1 -0
  101. data/screen_test/settings/align/box_right.rb +21 -0
  102. data/screen_test/settings/align/children_center.frame +1 -0
  103. data/screen_test/settings/align/children_center.rb +15 -0
  104. data/screen_test/settings/align/children_left.frame +1 -0
  105. data/screen_test/settings/align/children_left.rb +15 -0
  106. data/screen_test/settings/align/children_right.frame +1 -0
  107. data/screen_test/settings/align/children_right.rb +15 -0
  108. data/screen_test/settings/align/grid_center.frame +1 -0
  109. data/screen_test/settings/align/grid_center.rb +18 -0
  110. data/screen_test/settings/align/grid_default.frame +1 -0
  111. data/screen_test/settings/align/grid_default.rb +17 -0
  112. data/screen_test/settings/align/grid_left.frame +1 -0
  113. data/screen_test/settings/align/grid_left.rb +18 -0
  114. data/screen_test/settings/align/grid_right.frame +1 -0
  115. data/screen_test/settings/align/grid_right.rb +18 -0
  116. data/screen_test/settings/ansi/bold.frame +1 -0
  117. data/screen_test/settings/ansi/bold.rb +14 -0
  118. data/screen_test/settings/ansi/color.frame +1 -0
  119. data/screen_test/settings/ansi/color.rb +37 -0
  120. data/screen_test/settings/ansi/underline.frame +1 -0
  121. data/screen_test/settings/ansi/underline.rb +14 -0
  122. data/screen_test/settings/border.frame +1 -0
  123. data/screen_test/settings/border.rb +13 -0
  124. data/screen_test/settings/flow/box_b2t.frame +1 -0
  125. data/screen_test/settings/flow/box_b2t.rb +26 -0
  126. data/screen_test/settings/flow/box_l2r.frame +1 -0
  127. data/screen_test/settings/flow/box_l2r.rb +26 -0
  128. data/screen_test/settings/flow/box_r2l.frame +1 -0
  129. data/screen_test/settings/flow/box_r2l.rb +26 -0
  130. data/screen_test/settings/flow/box_t2b.frame +1 -0
  131. data/screen_test/settings/flow/box_t2b.rb +26 -0
  132. data/screen_test/settings/flow/grid_b2t.frame +1 -0
  133. data/screen_test/settings/flow/grid_b2t.rb +14 -0
  134. data/screen_test/settings/flow/grid_l2r.frame +1 -0
  135. data/screen_test/settings/flow/grid_l2r.rb +14 -0
  136. data/screen_test/settings/flow/grid_r2l.frame +1 -0
  137. data/screen_test/settings/flow/grid_r2l.rb +14 -0
  138. data/screen_test/settings/flow/grid_t2b.frame +1 -0
  139. data/screen_test/settings/flow/grid_t2b.rb +14 -0
  140. data/screen_test/settings/height/box.frame +1 -0
  141. data/screen_test/settings/height/box.rb +13 -0
  142. data/screen_test/settings/height/box_border_sizing.frame +1 -0
  143. data/screen_test/settings/height/box_border_sizing.rb +15 -0
  144. data/screen_test/settings/height/grid.frame +1 -0
  145. data/screen_test/settings/height/grid.rb +14 -0
  146. data/screen_test/settings/height/overflow_box.frame +1 -0
  147. data/screen_test/settings/height/overflow_box.rb +13 -0
  148. data/screen_test/settings/height/overflow_box_l2r.frame +1 -0
  149. data/screen_test/settings/height/overflow_box_l2r.rb +17 -0
  150. data/screen_test/settings/height/overflow_box_t2b.frame +1 -0
  151. data/screen_test/settings/height/overflow_box_t2b.rb +16 -0
  152. data/screen_test/settings/height/overflow_grid.frame +1 -0
  153. data/screen_test/settings/height/overflow_grid.rb +16 -0
  154. data/screen_test/settings/margin.frame +1 -0
  155. data/screen_test/settings/margin.rb +16 -0
  156. data/screen_test/settings/padding.frame +1 -0
  157. data/screen_test/settings/padding.rb +13 -0
  158. data/screen_test/settings/position/box_left.frame +1 -0
  159. data/screen_test/settings/position/box_left.rb +17 -0
  160. data/screen_test/settings/position/box_left_negative.frame +1 -0
  161. data/screen_test/settings/position/box_left_negative.rb +17 -0
  162. data/screen_test/settings/position/box_top.frame +1 -0
  163. data/screen_test/settings/position/box_top.rb +17 -0
  164. data/screen_test/settings/position/box_top_negative.frame +1 -0
  165. data/screen_test/settings/position/box_top_negative.rb +17 -0
  166. data/screen_test/settings/position/grid_left.frame +1 -0
  167. data/screen_test/settings/position/grid_left.rb +18 -0
  168. data/screen_test/settings/position/grid_left_negative.frame +1 -0
  169. data/screen_test/settings/position/grid_left_negative.rb +18 -0
  170. data/screen_test/settings/position/grid_top.frame +1 -0
  171. data/screen_test/settings/position/grid_top.rb +18 -0
  172. data/screen_test/settings/position/grid_top_negative.frame +1 -0
  173. data/screen_test/settings/position/grid_top_negative.rb +18 -0
  174. data/screen_test/settings/scroll/horiz_box.frame +1 -0
  175. data/screen_test/settings/scroll/horiz_box.rb +17 -0
  176. data/screen_test/settings/scroll/horiz_box_align_center.rb +18 -0
  177. data/screen_test/settings/scroll/horiz_box_align_right.rb +18 -0
  178. data/screen_test/settings/scroll/vert_box.frame +1 -0
  179. data/screen_test/settings/scroll/vert_box.rb +20 -0
  180. data/screen_test/settings/title_font.frame +1 -0
  181. data/screen_test/settings/title_font.rb +12 -0
  182. data/screen_test/settings/valign/box_around.frame +1 -0
  183. data/screen_test/settings/valign/box_around.rb +17 -0
  184. data/screen_test/settings/valign/box_between.frame +1 -0
  185. data/screen_test/settings/valign/box_between.rb +17 -0
  186. data/screen_test/settings/valign/box_bottom.frame +1 -0
  187. data/screen_test/settings/valign/box_bottom.rb +17 -0
  188. data/screen_test/settings/valign/box_default.frame +1 -0
  189. data/screen_test/settings/valign/box_default.rb +16 -0
  190. data/screen_test/settings/valign/box_evenly.frame +1 -0
  191. data/screen_test/settings/valign/box_evenly.rb +17 -0
  192. data/screen_test/settings/valign/box_middle.frame +1 -0
  193. data/screen_test/settings/valign/box_middle.rb +17 -0
  194. data/screen_test/settings/valign/box_top.frame +1 -0
  195. data/screen_test/settings/valign/box_top.rb +17 -0
  196. data/screen_test/settings/valign/grid_bottom.frame +1 -0
  197. data/screen_test/settings/valign/grid_bottom.rb +15 -0
  198. data/screen_test/settings/valign/grid_default.frame +1 -0
  199. data/screen_test/settings/valign/grid_default.rb +14 -0
  200. data/screen_test/settings/valign/grid_middle.frame +1 -0
  201. data/screen_test/settings/valign/grid_middle.rb +15 -0
  202. data/screen_test/settings/valign/grid_top.frame +1 -0
  203. data/screen_test/settings/valign/grid_top.rb +15 -0
  204. data/screen_test/settings/width/box_border_sizing.frame +1 -0
  205. data/screen_test/settings/width/box_border_sizing.rb +15 -0
  206. data/screen_test/settings/width/box_content.frame +1 -0
  207. data/screen_test/settings/width/box_content.rb +15 -0
  208. data/screen_test/settings/width/box_default.frame +1 -0
  209. data/screen_test/settings/width/box_default.rb +14 -0
  210. data/screen_test/settings/width/grid.frame +1 -0
  211. data/screen_test/settings/width/grid.rb +14 -0
  212. data/screen_test/settings/width/overflow_align_center.frame +1 -0
  213. data/screen_test/settings/width/overflow_align_center.rb +14 -0
  214. data/screen_test/settings/width/overflow_align_right.frame +1 -0
  215. data/screen_test/settings/width/overflow_align_right.rb +14 -0
  216. data/screen_test/settings/width/overflow_box.frame +1 -0
  217. data/screen_test/settings/width/overflow_box.rb +13 -0
  218. data/screen_test/settings/width/overflow_box_l2r.frame +1 -0
  219. data/screen_test/settings/width/overflow_box_l2r.rb +16 -0
  220. data/screen_test/settings/width/overflow_box_t2b.frame +1 -0
  221. data/screen_test/settings/width/overflow_box_t2b.rb +17 -0
  222. data/screen_test/settings/width/overflow_grid.frame +1 -0
  223. data/screen_test/settings/width/overflow_grid.rb +14 -0
  224. data/tools/whirled_peas/tools/screen_tester.rb +285 -0
  225. metadata +213 -15
  226. data/bin/title_fonts +0 -6
  227. data/lib/whirled_peas/frame.rb +0 -7
  228. data/lib/whirled_peas/frame/event_loop.rb +0 -91
  229. data/lib/whirled_peas/frame/print_consumer.rb +0 -33
  230. data/lib/whirled_peas/frame/producer.rb +0 -61
  231. data/lib/whirled_peas/template.rb +0 -5
  232. data/lib/whirled_peas/template/element.rb +0 -230
  233. data/lib/whirled_peas/template/settings.rb +0 -530
  234. data/lib/whirled_peas/ui.rb +0 -5
  235. data/lib/whirled_peas/ui/canvas.rb +0 -68
  236. data/lib/whirled_peas/ui/painter.rb +0 -287
  237. data/lib/whirled_peas/ui/screen.rb +0 -63
  238. data/lib/whirled_peas/utils/color.rb +0 -101
data/Rakefile CHANGED
@@ -1,6 +1,12 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- task :default => :spec
6
+ task :screen_test do
7
+ require_relative 'tools/whirled_peas/tools/screen_tester'
8
+ WhirledPeas::Tools::ScreenTester.run_all
9
+ end
10
+
11
+ task ci: %i[spec screen_test]
12
+ task default: :ci
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'whirled_peas'
5
+ require 'whirled_peas/utils/ansi'
6
+
7
+ module WhirledPeas
8
+ print Utils::Ansi.clear
9
+ print Utils::Ansi.cursor_visible(true)
10
+ STDOUT.flush
11
+ end
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'whirled_peas'
5
+ require 'whirled_peas/utils/formatted_string'
6
+
7
+ require_relative '../tools/whirled_peas/tools/screen_tester'
8
+
9
+ def print_usage(exit_code=0)
10
+ puts "Usage: #{$0} [file] [options]"
11
+ puts
12
+ puts 'If not file or options are provide, all tests are run'
13
+ puts
14
+ puts 'If no file is provided, the supported options are'
15
+ puts ' --help print this usage statement and exit'
16
+ puts ' --view-pending interactively display and optionally save rendered output for each pending test'
17
+ puts ' --view-failed interactively display and optionally save rendered output for each faiing test'
18
+ puts
19
+ puts 'If a screen test file is provided as the first argument, the supported options are'
20
+ puts ' --run run screen test for given file'
21
+ puts ' --view interactively display and optionally save the file\'s test output'
22
+ puts ' --template print out template tree for the test template'
23
+ puts ' --debug render the test template without displying it, printing out debug information'
24
+ exit(exit_code)
25
+ end
26
+
27
+ module WhirledPeas
28
+ if ARGV.length == 0
29
+ Tools::ScreenTester.run_all
30
+ elsif ARGV.length == 1
31
+ option = ARGV[0]
32
+ case option
33
+ when '--help'
34
+ print_usage
35
+ when '--view-pending'
36
+ Tools::ScreenTester.view_pending
37
+ when '--view-failed'
38
+ Tools::ScreenTester.view_failed
39
+ else
40
+ print_usage(1)
41
+ end
42
+ elsif ARGV.length == 2
43
+ file, option = ARGV
44
+ case option
45
+ when '--run'
46
+ tester = Tools::ScreenTester.new(file)
47
+ if tester.pending?
48
+ puts Utils::FormattedString.new('Pending', Settings::TextColor::YELLOW)
49
+ puts "Run `#{$0} #{file} --view` to view and optionally save ouput."
50
+ elsif tester.failed?
51
+ puts Utils::FormattedString.new('Failed', Settings::TextColor::RED)
52
+ puts "Run `#{$0} #{file} --view` to compare and optionally save ouput."
53
+ else
54
+ puts Utils::FormattedString.new('Pass', Settings::TextColor::GREEN)
55
+ end
56
+ when '--view'
57
+ Tools::ScreenTester.new(file).view
58
+ when '--template'
59
+ Tools::ScreenTester.new(file).template
60
+ when '--debug'
61
+ Tools::ScreenTester.new(file).debug
62
+ else
63
+ print_usage(1)
64
+ end
65
+ else
66
+ print_usage(1)
67
+ end
68
+ end
@@ -0,0 +1,52 @@
1
+ require 'bundler/setup'
2
+ require 'whirled_peas'
3
+
4
+ class TemplateFactory
5
+ TITLE_FONT = :default #roman
6
+ PRIMARY_COLOR = :bright_blue
7
+ SECONDARY_COLOR = :blue
8
+ BG_COLOR = :bright_white
9
+
10
+ def build(name, args)
11
+ WhirledPeas.template do |composer, settings|
12
+ settings.set_padding(left: 10, top: 6, right: 10, bottom: 6)
13
+ settings.align = :center
14
+ settings.width = 120
15
+ settings.flow = :t2b
16
+ settings.bold = true
17
+ settings.bg_color = BG_COLOR
18
+
19
+ composer.add_box do |composer, settings|
20
+ composer.add_text do |_, settings|
21
+ settings.title_font = TITLE_FONT
22
+ settings.color = PRIMARY_COLOR
23
+ 'Visualize'
24
+ end
25
+ end
26
+ composer.add_box do |_, settings|
27
+ settings.set_margin(top: 1)
28
+ settings.color = SECONDARY_COLOR
29
+ "your code's execution with"
30
+ end
31
+ composer.add_box do |composer, settings|
32
+ settings.set_margin(top: 1)
33
+ composer.add_text do |_, settings|
34
+ settings.title_font = TITLE_FONT
35
+ settings.color = PRIMARY_COLOR
36
+ 'Whirled Peas'
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ class Application
44
+ def start(producer)
45
+ producer.add_frame('intro', duration: 5)
46
+ end
47
+ end
48
+
49
+ WhirledPeas.configure do |config|
50
+ config.template_factory = TemplateFactory.new
51
+ config.application = Application.new
52
+ end
@@ -0,0 +1,54 @@
1
+ require 'bundler/setup'
2
+ require 'whirled_peas'
3
+
4
+ class TemplateFactory
5
+ HPADDING = 0
6
+ VPADDING = 0
7
+ ITEM_COUNT = 64
8
+
9
+ def build(name, args)
10
+ top = args[:top]
11
+ WhirledPeas.template do |composer, settings|
12
+ settings.color = :green
13
+ composer.add_box('Vert') do |composer, settings|
14
+ settings.bg_color = :bright_red
15
+ settings.full_border(color: :blue)
16
+ settings.set_scrollbar(vert: true)
17
+ settings.height = 12
18
+ composer.add_box('Inner') do |composer, settings|
19
+ settings.flow = :t2b
20
+ settings.set_padding(left: HPADDING, right: HPADDING, top: VPADDING, bottom: VPADDING)
21
+ settings.set_position(top: top)
22
+ ITEM_COUNT.times do |i|
23
+ composer.add_text { "%2d" % i }
24
+ end
25
+ end
26
+ end
27
+ composer.add_box('Horiz') do |composer, settings|
28
+ settings.bg_color = :bright_red
29
+ settings.full_border(color: :blue)
30
+ settings.set_padding(left: HPADDING, right: HPADDING, top: VPADDING, bottom: VPADDING)
31
+ settings.set_scrollbar(horiz: true)
32
+ settings.width = 12
33
+ composer.add_box('Inner') do |composer, settings|
34
+ settings.set_position(left: top)
35
+ ITEM_COUNT.times.map { |i| (i % 10).to_s }.join
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ class Application
43
+ def start(producer)
44
+ producer.frameset(5, easing: :bezier) do |fs|
45
+ 53.times { |i| fs.add_frame('intro', { top: -i }) }
46
+ end
47
+ producer.add_frame('hold', duration: 1, args: { top: -52})
48
+ end
49
+ end
50
+
51
+ WhirledPeas.configure do |config|
52
+ config.template_factory = TemplateFactory.new
53
+ config.application = Application.new
54
+ end
@@ -1,11 +1,8 @@
1
- require 'logger'
2
-
3
- require 'whirled_peas/errors'
4
-
1
+ require 'whirled_peas/animator'
5
2
  require 'whirled_peas/config'
6
- require 'whirled_peas/frame'
7
- require 'whirled_peas/template'
8
- require 'whirled_peas/ui'
3
+ require 'whirled_peas/errors'
4
+ require 'whirled_peas/graphics'
5
+ require 'whirled_peas/settings'
9
6
  require 'whirled_peas/utils'
10
7
  require 'whirled_peas/version'
11
8
 
@@ -19,10 +16,7 @@ module WhirledPeas
19
16
  end
20
17
 
21
18
  def self.template(&block)
22
- require 'whirled_peas/template/element'
23
-
24
- template = UI::Template.new
25
- yield template, template.settings
26
- template
19
+ require 'whirled_peas/graphics/composer'
20
+ Graphics::Composer.build(&block)
27
21
  end
28
22
  end
@@ -0,0 +1,5 @@
1
+ module WhirledPeas
2
+ module Animator
3
+ end
4
+ private_constant :Animator
5
+ end
@@ -0,0 +1,17 @@
1
+ module WhirledPeas
2
+ module Animator
3
+ class DebugConsumer
4
+ def add_frameset(frameset)
5
+ require 'json'
6
+
7
+ frameset.each_frame do |frame, args|
8
+ puts [frame, *(JSON.generate(args) unless args.empty?)].join(' ')
9
+ end
10
+ end
11
+
12
+ def process
13
+ # no op
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,72 @@
1
+ module WhirledPeas
2
+ module Animator
3
+ class Easing
4
+ # Implementations of available ease-in functions. Ease-out and ease-in-out can all be
5
+ # derived from ease-in.
6
+ EASING = {
7
+ bezier: proc do |value|
8
+ value /= 2
9
+ 2 * value * value * (3 - 2 * value)
10
+ end,
11
+ linear: proc { |value| value },
12
+ parametric: proc do |value|
13
+ value /= 2
14
+ squared = value * value
15
+ 2 * squared / (2 * (squared - value) + 1)
16
+ end,
17
+ quadratic: proc do |value|
18
+ value * value
19
+ end
20
+ }
21
+
22
+ EFFECTS = %i[in out in_out]
23
+
24
+ def initialize(easing=:linear, effect=:in_out)
25
+ unless EASING.key?(easing)
26
+ raise ArgumentError,
27
+ "Invalid easing function: #{easing}, expecting one of #{EASING.keys.join(', ')}"
28
+ end
29
+ unless EFFECTS.include?(effect)
30
+ raise ArgumentError,
31
+ "Invalid effect: #{effect}, expecting one of #{EFFECTS.join(', ')}"
32
+ end
33
+ @easing = easing
34
+ @effect = effect
35
+ end
36
+
37
+ def ease(value)
38
+ case effect
39
+ when :in
40
+ ease_in(value)
41
+ when :out
42
+ ease_out(value)
43
+ else
44
+ ease_in_out(value)
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ attr_reader :easing, :effect
51
+
52
+ # The procs in EASING define the ease-in functions, so we simply need
53
+ # to invoke the function with the given normalized value
54
+ def ease_in(value)
55
+ EASING[easing].call(value)
56
+ end
57
+
58
+ # The ease-out function will be the ease-in function rotated 180 degrees.
59
+ def ease_out(value)
60
+ 1 - EASING[easing].call(1 - value)
61
+ end
62
+
63
+ def ease_in_out(value)
64
+ if value < 0.5
65
+ ease_in(value * 2) / 2
66
+ else
67
+ 0.5 + ease_out(2 * value - 1) / 2
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,5 @@
1
+ module WhirledPeas
2
+ module Animator
3
+ Frame = Struct.new(:name, :args)
4
+ end
5
+ end
@@ -0,0 +1,33 @@
1
+ require_relative 'easing'
2
+ require_relative 'frame'
3
+
4
+ module WhirledPeas
5
+ module Animator
6
+ class Frameset
7
+ def initialize(frame_slots, easing, effect)
8
+ @frame_slots = frame_slots
9
+ @easing = Easing.new(easing, effect)
10
+ @frames = []
11
+ end
12
+
13
+ def add_frame(name, args={})
14
+ frames << [name, args]
15
+ end
16
+
17
+ # Yield each frame in an "eased" order
18
+ def each_frame(&block)
19
+ frame_slots.times do |i|
20
+ input = i.to_f / (frame_slots - 1)
21
+ eased_value = @easing.ease(input)
22
+ index = (eased_value * (frames.length - 1)).floor
23
+ yield *frames[index]
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :frame_slots, :easing, :frames
30
+ end
31
+ private_constant :Frameset
32
+ end
33
+ end
@@ -0,0 +1,35 @@
1
+ require_relative 'easing'
2
+ require_relative 'frameset'
3
+
4
+ module WhirledPeas
5
+ module Animator
6
+ class Producer
7
+ def self.produce(consumer, refresh_rate)
8
+ producer = new(consumer, refresh_rate)
9
+ yield producer
10
+ consumer.process
11
+ end
12
+
13
+ def initialize(consumer, refresh_rate)
14
+ @consumer = consumer
15
+ @refresh_rate = refresh_rate
16
+ end
17
+
18
+ def add_frame(name, duration: nil, args: {})
19
+ frameset(duration || 1 / refresh_rate) do |fs|
20
+ fs.add_frame(name, args)
21
+ end
22
+ end
23
+
24
+ def frameset(duration, easing: :linear, effect: :in_out, &block)
25
+ fs = Frameset.new((duration * refresh_rate).round, easing, effect)
26
+ yield fs
27
+ consumer.add_frameset(fs)
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :consumer, :refresh_rate
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,31 @@
1
+ require 'whirled_peas/graphics/renderer'
2
+ require 'whirled_peas/utils/ansi'
3
+
4
+ module WhirledPeas
5
+ module Animator
6
+ class RendererConsumer
7
+ def initialize(template_factory, device, width, height)
8
+ @template_factory = template_factory
9
+ @device = device
10
+ @width = width
11
+ @height = height
12
+ @renders = []
13
+ end
14
+
15
+ def add_frameset(frameset)
16
+ frameset.each_frame do |frame, args|
17
+ template = template_factory.build(frame, args)
18
+ renders << Graphics::Renderer.new(template, width, height).paint
19
+ end
20
+ end
21
+
22
+ def process
23
+ device.handle_renders(renders)
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :template_factory, :device, :width, :height, :renders
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ module WhirledPeas
2
+ module Command
3
+ end
4
+ private_constant :Command
5
+ end