whirled_peas 0.9.1 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (255) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -2
  3. data/CHANGELOG.md +23 -0
  4. data/README.md +9 -1049
  5. data/doc/application.md +92 -0
  6. data/doc/cli.md +115 -0
  7. data/doc/components.md +51 -0
  8. data/doc/easing.md +257 -0
  9. data/doc/elements.md +69 -0
  10. data/doc/screen_test.md +22 -0
  11. data/doc/settings.md +466 -0
  12. data/doc/template_factory.md +53 -0
  13. data/doc/themes.md +50 -0
  14. data/examples/components.rb +33 -0
  15. data/examples/graph.rb +1 -1
  16. data/examples/scrolling.rb +8 -19
  17. data/lib/data/themes.yaml +15 -0
  18. data/lib/whirled_peas.rb +31 -9
  19. data/lib/whirled_peas/animator/debug_consumer.rb +2 -2
  20. data/lib/whirled_peas/animator/easing.rb +57 -0
  21. data/lib/whirled_peas/animator/frameset.rb +13 -8
  22. data/lib/whirled_peas/animator/producer.rb +7 -8
  23. data/lib/whirled_peas/animator/renderer_consumer.rb +10 -5
  24. data/lib/whirled_peas/command/config_command.rb +3 -3
  25. data/lib/whirled_peas/command/frames.rb +1 -3
  26. data/lib/whirled_peas/command/play.rb +9 -7
  27. data/lib/whirled_peas/command/record.rb +1 -3
  28. data/lib/whirled_peas/command/still.rb +6 -2
  29. data/lib/whirled_peas/command/themes.rb +78 -0
  30. data/lib/whirled_peas/command_line.rb +3 -1
  31. data/lib/whirled_peas/component.rb +35 -0
  32. data/lib/whirled_peas/component/list_with_active.rb +89 -0
  33. data/lib/whirled_peas/config.rb +1 -8
  34. data/lib/whirled_peas/device/null_device.rb +1 -1
  35. data/lib/whirled_peas/device/output_file.rb +2 -2
  36. data/lib/whirled_peas/device/rendered_frame.rb +12 -0
  37. data/lib/whirled_peas/device/screen.rb +7 -8
  38. data/lib/whirled_peas/graphics/box_painter.rb +4 -4
  39. data/lib/whirled_peas/graphics/composer.rb +9 -2
  40. data/lib/whirled_peas/graphics/container_coords.rb +23 -25
  41. data/lib/whirled_peas/graphics/container_dimensions.rb +24 -0
  42. data/lib/whirled_peas/graphics/container_painter.rb +27 -139
  43. data/lib/whirled_peas/graphics/debugger.rb +2 -7
  44. data/lib/whirled_peas/graphics/graph_painter.rb +31 -24
  45. data/lib/whirled_peas/graphics/pixel_grid.rb +81 -0
  46. data/lib/whirled_peas/graphics/renderer.rb +4 -5
  47. data/lib/whirled_peas/graphics/scrollbar_helper.rb +126 -0
  48. data/lib/whirled_peas/null_logger.rb +0 -1
  49. data/lib/whirled_peas/settings/bg_color.rb +5 -1
  50. data/lib/whirled_peas/settings/border.rb +26 -5
  51. data/lib/whirled_peas/settings/color.rb +8 -4
  52. data/lib/whirled_peas/settings/container_settings.rb +14 -7
  53. data/lib/whirled_peas/settings/debugger.rb +3 -1
  54. data/lib/whirled_peas/settings/element_settings.rb +18 -6
  55. data/lib/whirled_peas/settings/graph_settings.rb +1 -1
  56. data/lib/whirled_peas/settings/position.rb +17 -5
  57. data/lib/whirled_peas/settings/text_color.rb +5 -0
  58. data/lib/whirled_peas/settings/text_settings.rb +1 -0
  59. data/lib/whirled_peas/settings/theme.rb +61 -0
  60. data/lib/whirled_peas/settings/theme_library.rb +69 -0
  61. data/lib/whirled_peas/utils/ansi.rb +4 -2
  62. data/lib/whirled_peas/utils/file_handler.rb +14 -9
  63. data/lib/whirled_peas/utils/formatted_string.rb +5 -3
  64. data/lib/whirled_peas/version.rb +1 -1
  65. data/screen_test/components/list_with_active/l2r_position_end.frame +1 -0
  66. data/screen_test/components/list_with_active/l2r_position_end.rb +16 -0
  67. data/screen_test/components/list_with_active/l2r_position_middle.frame +1 -0
  68. data/screen_test/components/list_with_active/l2r_position_middle.rb +16 -0
  69. data/screen_test/components/list_with_active/l2r_position_start.frame +1 -0
  70. data/screen_test/components/list_with_active/l2r_position_start.rb +16 -0
  71. data/screen_test/components/list_with_active/l2r_separator.frame +1 -0
  72. data/screen_test/components/list_with_active/l2r_separator.rb +17 -0
  73. data/screen_test/components/list_with_active/t2b_position_end.frame +1 -0
  74. data/screen_test/components/list_with_active/t2b_position_end.rb +17 -0
  75. data/screen_test/components/list_with_active/t2b_position_middle.frame +1 -0
  76. data/screen_test/components/list_with_active/t2b_position_middle.rb +17 -0
  77. data/screen_test/components/list_with_active/t2b_position_start.frame +1 -0
  78. data/screen_test/components/list_with_active/t2b_position_start.rb +17 -0
  79. data/screen_test/components/list_with_active/t2b_separator.frame +1 -0
  80. data/screen_test/components/list_with_active/t2b_separator.rb +18 -0
  81. data/screen_test/elements/box.frame +1 -1
  82. data/screen_test/elements/box.rb +1 -1
  83. data/screen_test/elements/graph_asc.frame +1 -0
  84. data/screen_test/elements/{graph.rb → graph_asc.rb} +1 -1
  85. data/screen_test/elements/graph_desc.frame +1 -0
  86. data/screen_test/elements/graph_desc.rb +12 -0
  87. data/screen_test/elements/graph_horiz.frame +1 -0
  88. data/screen_test/elements/graph_horiz.rb +12 -0
  89. data/screen_test/elements/graph_sin.frame +1 -0
  90. data/screen_test/elements/graph_sin.rb +12 -0
  91. data/screen_test/elements/grid.frame +1 -1
  92. data/screen_test/elements/grid.rb +1 -1
  93. data/screen_test/elements/screen_overflow_x.frame +1 -1
  94. data/screen_test/elements/screen_overflow_x.rb +1 -1
  95. data/screen_test/elements/screen_overflow_y.frame +1 -1
  96. data/screen_test/elements/screen_overflow_y.rb +1 -1
  97. data/screen_test/elements/text.frame +1 -1
  98. data/screen_test/elements/text.rb +1 -1
  99. data/screen_test/elements/text_multiline.frame +1 -1
  100. data/screen_test/elements/text_multiline.rb +1 -1
  101. data/screen_test/elements/theme.frame +1 -0
  102. data/screen_test/elements/theme.rb +27 -0
  103. data/screen_test/settings/align/box_around.frame +1 -1
  104. data/screen_test/settings/align/box_around.rb +1 -1
  105. data/screen_test/settings/align/box_between.frame +1 -1
  106. data/screen_test/settings/align/box_between.rb +1 -1
  107. data/screen_test/settings/align/box_center.frame +1 -1
  108. data/screen_test/settings/align/box_center.rb +1 -1
  109. data/screen_test/settings/align/box_default.frame +1 -1
  110. data/screen_test/settings/align/box_default.rb +1 -1
  111. data/screen_test/settings/align/box_evenly.frame +1 -1
  112. data/screen_test/settings/align/box_evenly.rb +1 -1
  113. data/screen_test/settings/align/box_left.frame +1 -1
  114. data/screen_test/settings/align/box_left.rb +1 -1
  115. data/screen_test/settings/align/box_right.frame +1 -1
  116. data/screen_test/settings/align/box_right.rb +1 -1
  117. data/screen_test/settings/align/children_center.frame +1 -1
  118. data/screen_test/settings/align/children_center.rb +1 -1
  119. data/screen_test/settings/align/children_left.frame +1 -1
  120. data/screen_test/settings/align/children_left.rb +1 -1
  121. data/screen_test/settings/align/children_right.frame +1 -1
  122. data/screen_test/settings/align/children_right.rb +1 -1
  123. data/screen_test/settings/align/grid_center.frame +1 -1
  124. data/screen_test/settings/align/grid_center.rb +1 -1
  125. data/screen_test/settings/align/grid_default.frame +1 -1
  126. data/screen_test/settings/align/grid_default.rb +1 -1
  127. data/screen_test/settings/align/grid_left.frame +1 -1
  128. data/screen_test/settings/align/grid_left.rb +1 -1
  129. data/screen_test/settings/align/grid_right.frame +1 -1
  130. data/screen_test/settings/align/grid_right.rb +1 -1
  131. data/screen_test/settings/ansi/bold.frame +1 -1
  132. data/screen_test/settings/ansi/bold.rb +1 -1
  133. data/screen_test/settings/ansi/color.frame +1 -1
  134. data/screen_test/settings/ansi/color.rb +1 -1
  135. data/screen_test/settings/ansi/underline.frame +1 -1
  136. data/screen_test/settings/ansi/underline.rb +1 -1
  137. data/screen_test/settings/border.frame +1 -1
  138. data/screen_test/settings/border.rb +1 -1
  139. data/screen_test/settings/content_start/box_bottom.frame +1 -0
  140. data/screen_test/settings/content_start/box_bottom.rb +17 -0
  141. data/screen_test/settings/content_start/box_left.frame +1 -0
  142. data/screen_test/settings/{position → content_start}/box_left.rb +2 -2
  143. data/screen_test/settings/content_start/box_left_negative.frame +1 -0
  144. data/screen_test/settings/{position → content_start}/box_left_negative.rb +2 -2
  145. data/screen_test/settings/content_start/box_right.frame +1 -0
  146. data/screen_test/settings/content_start/box_right.rb +17 -0
  147. data/screen_test/settings/content_start/box_top.frame +1 -0
  148. data/screen_test/settings/{position → content_start}/box_top.rb +2 -2
  149. data/screen_test/settings/content_start/box_top_negative.frame +1 -0
  150. data/screen_test/settings/{position → content_start}/box_top_negative.rb +2 -2
  151. data/screen_test/settings/content_start/grid_left.frame +1 -0
  152. data/screen_test/settings/{position → content_start}/grid_left.rb +2 -2
  153. data/screen_test/settings/content_start/grid_left_negative.frame +1 -0
  154. data/screen_test/settings/{position → content_start}/grid_left_negative.rb +2 -2
  155. data/screen_test/settings/content_start/grid_top.frame +1 -0
  156. data/screen_test/settings/{position → content_start}/grid_top.rb +2 -2
  157. data/screen_test/settings/content_start/grid_top_negative.frame +1 -0
  158. data/screen_test/settings/{position → content_start}/grid_top_negative.rb +2 -2
  159. data/screen_test/settings/flow/box_b2t.frame +1 -1
  160. data/screen_test/settings/flow/box_b2t.rb +1 -1
  161. data/screen_test/settings/flow/box_l2r.frame +1 -1
  162. data/screen_test/settings/flow/box_l2r.rb +1 -1
  163. data/screen_test/settings/flow/box_r2l.frame +1 -1
  164. data/screen_test/settings/flow/box_r2l.rb +1 -1
  165. data/screen_test/settings/flow/box_t2b.frame +1 -1
  166. data/screen_test/settings/flow/box_t2b.rb +1 -1
  167. data/screen_test/settings/flow/grid_b2t.frame +1 -1
  168. data/screen_test/settings/flow/grid_b2t.rb +1 -1
  169. data/screen_test/settings/flow/grid_l2r.frame +1 -1
  170. data/screen_test/settings/flow/grid_l2r.rb +1 -1
  171. data/screen_test/settings/flow/grid_r2l.frame +1 -1
  172. data/screen_test/settings/flow/grid_r2l.rb +1 -1
  173. data/screen_test/settings/flow/grid_t2b.frame +1 -1
  174. data/screen_test/settings/flow/grid_t2b.rb +1 -1
  175. data/screen_test/settings/height/box.frame +1 -1
  176. data/screen_test/settings/height/box.rb +1 -1
  177. data/screen_test/settings/height/box_border_sizing.frame +1 -1
  178. data/screen_test/settings/height/box_border_sizing.rb +1 -1
  179. data/screen_test/settings/height/grid.frame +1 -1
  180. data/screen_test/settings/height/grid.rb +1 -1
  181. data/screen_test/settings/height/overflow_box.frame +1 -1
  182. data/screen_test/settings/height/overflow_box.rb +1 -1
  183. data/screen_test/settings/height/overflow_box_l2r.frame +1 -1
  184. data/screen_test/settings/height/overflow_box_l2r.rb +1 -1
  185. data/screen_test/settings/height/overflow_box_t2b.frame +1 -1
  186. data/screen_test/settings/height/overflow_box_t2b.rb +1 -1
  187. data/screen_test/settings/height/overflow_grid.frame +1 -1
  188. data/screen_test/settings/height/overflow_grid.rb +1 -1
  189. data/screen_test/settings/margin.frame +1 -1
  190. data/screen_test/settings/margin.rb +1 -1
  191. data/screen_test/settings/padding.frame +1 -1
  192. data/screen_test/settings/padding.rb +1 -1
  193. data/screen_test/settings/scroll/horiz_box.frame +1 -1
  194. data/screen_test/settings/scroll/horiz_box.rb +3 -5
  195. data/screen_test/settings/scroll/horiz_box_align_center.rb +3 -5
  196. data/screen_test/settings/scroll/horiz_box_align_right.rb +3 -5
  197. data/screen_test/settings/scroll/vert_box.frame +1 -1
  198. data/screen_test/settings/scroll/vert_box.rb +6 -8
  199. data/screen_test/settings/title_font.frame +1 -1
  200. data/screen_test/settings/title_font.rb +1 -1
  201. data/screen_test/settings/valign/box_around.frame +1 -1
  202. data/screen_test/settings/valign/box_around.rb +1 -1
  203. data/screen_test/settings/valign/box_between.frame +1 -1
  204. data/screen_test/settings/valign/box_between.rb +1 -1
  205. data/screen_test/settings/valign/box_bottom.frame +1 -1
  206. data/screen_test/settings/valign/box_bottom.rb +1 -1
  207. data/screen_test/settings/valign/box_default.frame +1 -1
  208. data/screen_test/settings/valign/box_default.rb +1 -1
  209. data/screen_test/settings/valign/box_evenly.frame +1 -1
  210. data/screen_test/settings/valign/box_evenly.rb +1 -1
  211. data/screen_test/settings/valign/box_middle.frame +1 -1
  212. data/screen_test/settings/valign/box_middle.rb +1 -1
  213. data/screen_test/settings/valign/box_top.frame +1 -1
  214. data/screen_test/settings/valign/box_top.rb +1 -1
  215. data/screen_test/settings/valign/grid_bottom.frame +1 -1
  216. data/screen_test/settings/valign/grid_bottom.rb +1 -1
  217. data/screen_test/settings/valign/grid_default.frame +1 -1
  218. data/screen_test/settings/valign/grid_default.rb +1 -1
  219. data/screen_test/settings/valign/grid_middle.frame +1 -1
  220. data/screen_test/settings/valign/grid_middle.rb +1 -1
  221. data/screen_test/settings/valign/grid_top.frame +1 -1
  222. data/screen_test/settings/valign/grid_top.rb +1 -1
  223. data/screen_test/settings/width/box_border_sizing.frame +1 -1
  224. data/screen_test/settings/width/box_border_sizing.rb +1 -1
  225. data/screen_test/settings/width/box_content.frame +1 -1
  226. data/screen_test/settings/width/box_content.rb +1 -1
  227. data/screen_test/settings/width/box_default.frame +1 -1
  228. data/screen_test/settings/width/box_default.rb +1 -1
  229. data/screen_test/settings/width/grid.frame +1 -1
  230. data/screen_test/settings/width/grid.rb +1 -1
  231. data/screen_test/settings/width/overflow_align_center.frame +1 -1
  232. data/screen_test/settings/width/overflow_align_center.rb +1 -1
  233. data/screen_test/settings/width/overflow_align_right.frame +1 -1
  234. data/screen_test/settings/width/overflow_align_right.rb +1 -1
  235. data/screen_test/settings/width/overflow_box.frame +1 -1
  236. data/screen_test/settings/width/overflow_box.rb +1 -1
  237. data/screen_test/settings/width/overflow_box_l2r.frame +1 -1
  238. data/screen_test/settings/width/overflow_box_l2r.rb +1 -1
  239. data/screen_test/settings/width/overflow_box_t2b.frame +1 -1
  240. data/screen_test/settings/width/overflow_box_t2b.rb +1 -1
  241. data/screen_test/settings/width/overflow_grid.frame +1 -1
  242. data/screen_test/settings/width/overflow_grid.rb +1 -1
  243. data/tools/whirled_peas/tools/screen_tester.rb +21 -3
  244. metadata +67 -22
  245. data/bin/easing +0 -33
  246. data/lib/whirled_peas/graphics/mock_screen.rb +0 -26
  247. data/screen_test/elements/graph.frame +0 -1
  248. data/screen_test/settings/position/box_left.frame +0 -1
  249. data/screen_test/settings/position/box_left_negative.frame +0 -1
  250. data/screen_test/settings/position/box_top.frame +0 -1
  251. data/screen_test/settings/position/box_top_negative.frame +0 -1
  252. data/screen_test/settings/position/grid_left.frame +0 -1
  253. data/screen_test/settings/position/grid_left_negative.frame +0 -1
  254. data/screen_test/settings/position/grid_top.frame +0 -1
  255. data/screen_test/settings/position/grid_top_negative.frame +0 -1
@@ -8,9 +8,9 @@ module WhirledPeas
8
8
  class ConfigCommand < Base
9
9
  def start
10
10
  require config_file
11
- rescue => e
12
- puts "Error loading #{config_file}"
13
- puts e.message
11
+ rescue LoadError => e
12
+ puts e
13
+ puts e.backtrace.join("\n")
14
14
  exit(1)
15
15
  end
16
16
 
@@ -13,9 +13,7 @@ module WhirledPeas
13
13
  require 'whirled_peas/animator/debug_consumer'
14
14
  require 'whirled_peas/animator/producer'
15
15
 
16
- Animator::Producer.produce(
17
- Animator::DebugConsumer.new, WhirledPeas.config.refresh_rate
18
- ) do |producer|
16
+ Animator::Producer.produce(Animator::DebugConsumer.new) do |producer|
19
17
  config.application.start(producer)
20
18
  end
21
19
  end
@@ -28,16 +28,18 @@ module WhirledPeas
28
28
  Utils::Ansi.with_screen do |width, height|
29
29
  consumer = Animator::RendererConsumer.new(
30
30
  WhirledPeas.config.template_factory,
31
- Device::Screen.new(WhirledPeas.config.refresh_rate),
31
+ Device::Screen.new,
32
32
  width,
33
33
  height
34
34
  )
35
- Animator::Producer.produce(
36
- consumer, WhirledPeas.config.refresh_rate
37
- ) do |producer|
35
+ Animator::Producer.produce(consumer) do |producer|
38
36
  config.application.start(producer)
39
37
  end
40
38
  end
39
+ rescue LoadError => e
40
+ puts e
41
+ puts e.backtrace.join("\n")
42
+ exit(1)
41
43
  end
42
44
 
43
45
  private
@@ -56,9 +58,9 @@ module WhirledPeas
56
58
  require 'whirled_peas/utils/file_handler'
57
59
 
58
60
  Utils::Ansi.with_screen do
59
- screen = Device::Screen.new(WhirledPeas.config.refresh_rate)
60
- renders = Utils::FileHandler.read(wpz_file)
61
- screen.handle_renders(renders)
61
+ screen = Device::Screen.new
62
+ rendered_frames = Utils::FileHandler.read(wpz_file)
63
+ screen.handle_rendered_frames(rendered_frames)
62
64
  end
63
65
  end
64
66
 
@@ -21,9 +21,7 @@ module WhirledPeas
21
21
  width,
22
22
  height
23
23
  )
24
- Animator::Producer.produce(
25
- consumer, WhirledPeas.config.refresh_rate
26
- ) do |producer|
24
+ Animator::Producer.produce(consumer) do |producer|
27
25
  config.application.start(producer)
28
26
  end
29
27
  end
@@ -1,3 +1,5 @@
1
+ require 'whirled_peas/device/rendered_frame'
2
+
1
3
  require_relative 'frame_command'
2
4
 
3
5
  module WhirledPeas
@@ -16,12 +18,14 @@ module WhirledPeas
16
18
  require 'whirled_peas/utils/ansi'
17
19
 
18
20
  Utils::Ansi.with_screen do |width, height|
19
- rendered = Graphics::Renderer.new(
21
+ strokes = Graphics::Renderer.new(
20
22
  WhirledPeas.config.template_factory.build(frame, frame_args),
21
23
  width,
22
24
  height
23
25
  ).paint
24
- Device::Screen.new(10000).handle_renders([rendered])
26
+ Device::Screen.new.handle_rendered_frames(
27
+ [Device::RenderedFrame.new(strokes, 0)]
28
+ )
25
29
  end
26
30
  end
27
31
  end
@@ -0,0 +1,78 @@
1
+ require 'whirled_peas/device/screen'
2
+ require 'whirled_peas/graphics/renderer'
3
+ require 'whirled_peas/settings/theme_library'
4
+
5
+ require_relative 'base'
6
+
7
+ module WhirledPeas
8
+ module Command
9
+ # Display a still frame with the specified arguments.
10
+ class Themes < Base
11
+ def self.description
12
+ 'List all themes with sample template rendered in the theme'
13
+ end
14
+
15
+ def start
16
+ super
17
+
18
+ require config_file unless config_file.nil?
19
+
20
+ theme_names = Settings::ThemeLibrary.theme_names
21
+ theme_names.each.with_index do |name, index|
22
+ template = WhirledPeas.template(name) do |composer, settings|
23
+ settings.full_border
24
+ settings.flow = :t2b
25
+ composer.add_text do |_, settings|
26
+ settings.title_font = :theme
27
+ name
28
+ end
29
+ composer.add_text do
30
+ name == Settings::ThemeLibrary.default_name ? ' (default)' : ''
31
+ end
32
+ composer.add_graph do |_, settings|
33
+ settings.height = 12
34
+ 20.times.map { |i| Math.sqrt(i) }
35
+ end
36
+ end
37
+ Utils::Ansi.with_screen do |width, height|
38
+ strokes = Graphics::Renderer.new(
39
+ template,
40
+ 80,
41
+ 30
42
+ ).paint
43
+ Device::Screen.new.handle_rendered_frames(
44
+ [Device::RenderedFrame.new(strokes, 0)]
45
+ )
46
+ end
47
+
48
+ if index < theme_names.length - 1
49
+ print 'See next theme? [Y/q] '
50
+ STDOUT.flush
51
+ break if gets.chomp == 'q'
52
+ end
53
+ end
54
+ rescue LoadError => e
55
+ puts e
56
+ puts e.backtrace.join("\n")
57
+ exit(1)
58
+ end
59
+
60
+ private
61
+
62
+ attr_reader :config_file
63
+
64
+ def validate!
65
+ super
66
+ config_file = args.shift
67
+ unless config_file.nil?
68
+ # We think we have a valid ruby config file, set the absolute path to @config
69
+ @config_file = config_file[0] == '/' ? config_file : File.join(Dir.pwd, config_file)
70
+ end
71
+ end
72
+
73
+ def options_usage
74
+ '[config file]'
75
+ end
76
+ end
77
+ end
78
+ end
@@ -5,6 +5,7 @@ require 'whirled_peas/command/help'
5
5
  require 'whirled_peas/command/play'
6
6
  require 'whirled_peas/command/record'
7
7
  require 'whirled_peas/command/still'
8
+ require 'whirled_peas/command/themes'
8
9
 
9
10
  module WhirledPeas
10
11
  class CommandLine
@@ -15,7 +16,8 @@ module WhirledPeas
15
16
  Command::Help,
16
17
  Command::Play,
17
18
  Command::Record,
18
- Command::Still
19
+ Command::Still,
20
+ Command::Themes
19
21
  ].map.with_object({}) { |c, h| h[c.command_name] = c }
20
22
 
21
23
  def initialize(args)
@@ -0,0 +1,35 @@
1
+ module WhirledPeas
2
+ module Component
3
+ module Factory
4
+ class << self
5
+ def register(name, klass)
6
+ classes[name] = klass
7
+ end
8
+
9
+ def build(name)
10
+ unless classes.key?(name)
11
+ expected = classes.keys.join(', ')
12
+ raise ArgumentError, "Unrecognized component: #{name.inspect}, expecting one of #{expected}"
13
+ end
14
+ @classes[name].new
15
+ end
16
+
17
+ private
18
+
19
+ def classes
20
+ return @classes if @classes
21
+ @classes = {}
22
+ Component.constants.each do |const|
23
+ next if const == name
24
+ klass = Component.const_get(const)
25
+ next unless klass.is_a?(Class)
26
+ name = const.to_s.gsub(/([a-z])([A-Z])/, '\1_\2').downcase.to_sym
27
+ @classes[name] = klass
28
+ end
29
+ @classes
30
+ end
31
+ end
32
+ end
33
+ end
34
+ private_constant :Component
35
+ end
@@ -0,0 +1,89 @@
1
+ module WhirledPeas
2
+ module Component
3
+ class ListWithActive
4
+ attr_accessor :active_index, :separator
5
+
6
+ attr_reader :items
7
+
8
+ attr_writer :flow, :viewport_size
9
+
10
+ def items=(value)
11
+ @items = value.map(&:to_s)
12
+ end
13
+
14
+ def flow
15
+ @flow || :l2r
16
+ end
17
+
18
+ def total_size
19
+ @total_size ||= if flow == :l2r
20
+ size = separator.nil? ? 0 : (items.count - 1) * separator.length
21
+ items.each { |item| size += item.length }
22
+ size
23
+ else
24
+ items.count + (separator.nil? ? 0 : items.count - 1)
25
+ end
26
+ end
27
+
28
+ def viewport_size
29
+ @viewport_size || total_size
30
+ end
31
+
32
+ def compose(composer, settings)
33
+ %i[items].each do |required_attr|
34
+ if send(required_attr).nil?
35
+ raise ArgumentError, "Required field #{required_attr} missing"
36
+ end
37
+ end
38
+
39
+ composer.add_box('ListWithActive') do |composer, settings|
40
+ settings.flow = flow
41
+ settings.align = :left
42
+ settings.full_border
43
+ curr_index = active_index || 0
44
+ if flow == :l2r
45
+ settings.width = viewport_size
46
+ active_start = separator.nil? ? 0 : curr_index * separator.length
47
+ items.first(curr_index).each do |item|
48
+ active_start += item.length
49
+ end
50
+ curr_size = items[curr_index].length
51
+ else
52
+ settings.height = viewport_size
53
+ active_start = curr_index + (separator.nil? ? 0 : curr_index)
54
+ curr_size = 1
55
+ end
56
+
57
+ if viewport_size < total_size
58
+ front_padding = (viewport_size - curr_size) * 0.667
59
+ offset = (active_start - front_padding).round
60
+ if offset < 0
61
+ offset = 0
62
+ elsif offset > total_size - viewport_size
63
+ offset = total_size - viewport_size
64
+ end
65
+
66
+ if flow == :l2r
67
+ settings.content_start.left = -offset
68
+ settings.scrollbar.horiz = true
69
+ else
70
+ settings.content_start.top = -offset
71
+ settings.scrollbar.vert = true
72
+ end
73
+ end
74
+
75
+ items.each.with_index do |item, index|
76
+ composer.add_text { separator } if !separator.nil? && index > 0
77
+ composer.add_text do |_, settings|
78
+ if index == active_index
79
+ settings.bg_color = :highlight
80
+ settings.color = :highlight
81
+ end
82
+ item
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -2,9 +2,6 @@ require 'logger'
2
2
 
3
3
  module WhirledPeas
4
4
  class Config
5
- # Refreshed rate measured in frames per second
6
- DEFAULT_REFRESH_RATE = 30
7
-
8
5
  DEFAULT_LOG_LEVEL = Logger::INFO
9
6
  DEFAULT_LOG_FILE = 'whirled_peas.log'
10
7
 
@@ -35,7 +32,7 @@ module WhirledPeas
35
32
  "[#{severity}] #{datetime.strftime('%Y-%m-%dT%H:%M:%S.%L')} (#{progname}) - #{msg}\n"
36
33
  end
37
34
 
38
- attr_writer :application, :template_factory, :refresh_rate, :log_level, :log_formatter, :log_file
35
+ attr_writer :application, :template_factory, :log_level, :log_formatter, :log_file
39
36
 
40
37
  def application
41
38
  unless @application
@@ -51,10 +48,6 @@ module WhirledPeas
51
48
  @template_factory
52
49
  end
53
50
 
54
- def refresh_rate
55
- @refresh_rate || DEFAULT_REFRESH_RATE
56
- end
57
-
58
51
  def log_level
59
52
  @log_level || DEFAULT_LOG_LEVEL
60
53
  end
@@ -1,7 +1,7 @@
1
1
  module WhirledPeas
2
2
  module Device
3
3
  class NullDevice
4
- def handle_renders(*)
4
+ def handle_rendered_frames(*)
5
5
  end
6
6
  end
7
7
  end
@@ -7,8 +7,8 @@ module WhirledPeas
7
7
  @file = file
8
8
  end
9
9
 
10
- def handle_renders(renders)
11
- Utils::FileHandler.write(file, renders)
10
+ def handle_rendered_frames(rendered_frames)
11
+ Utils::FileHandler.write(file, rendered_frames)
12
12
  end
13
13
 
14
14
  private
@@ -0,0 +1,12 @@
1
+ module WhirledPeas
2
+ module Device
3
+ class RenderedFrame
4
+ attr_reader :strokes, :duration
5
+
6
+ def initialize(strokes, duration)
7
+ @strokes = strokes
8
+ @duration = duration
9
+ end
10
+ end
11
+ end
12
+ end
@@ -3,24 +3,23 @@ require 'highline'
3
3
  module WhirledPeas
4
4
  module Device
5
5
  class Screen
6
- def initialize(refresh_rate, output: STDOUT)
7
- @refresh_rate = refresh_rate
6
+ def initialize(output: STDOUT)
8
7
  @output = output
9
8
  end
10
9
 
11
- def handle_renders(renders)
12
- renders.each do |strokes|
13
- frame_at = Time.now
14
- output.print(strokes)
10
+ def handle_rendered_frames(rendered_frames)
11
+ next_frame_at = Time.now
12
+ rendered_frames.each do |rendered_frame|
13
+ next_frame_at += rendered_frame.duration
14
+ output.print(rendered_frame.strokes)
15
15
  output.flush
16
- next_frame_at = frame_at + 1.0 / refresh_rate
17
16
  sleep([0, next_frame_at - Time.now].max)
18
17
  end
19
18
  end
20
19
 
21
20
  private
22
21
 
23
- attr_reader :refresh_rate, :output
22
+ attr_reader :output
24
23
  end
25
24
  end
26
25
  end
@@ -55,8 +55,8 @@ module WhirledPeas
55
55
  private
56
56
 
57
57
  def paint_horizontally(canvas, canvas_coords, &block)
58
- stroke_left = canvas_coords.content_left
59
- stroke_top = canvas_coords.content_top
58
+ stroke_left = canvas_coords.offset_content_left
59
+ stroke_top = canvas_coords.offset_content_top
60
60
  children_width = 0
61
61
  each_child { |c| children_width += c.dimensions.outer_width }
62
62
  left_offset, spacing_offset = horiz_justify_offset(children_width)
@@ -76,8 +76,8 @@ module WhirledPeas
76
76
  end
77
77
 
78
78
  def paint_vertically(canvas, canvas_coords, &block)
79
- stroke_left = canvas_coords.content_left
80
- stroke_top = canvas_coords.content_top
79
+ stroke_left = canvas_coords.offset_content_left
80
+ stroke_top = canvas_coords.offset_content_top
81
81
  children_height = 0
82
82
  each_child { |c| children_height += c.dimensions.outer_height }
83
83
  top_offset, spacing_offset = vert_justify_offset(children_height)
@@ -2,6 +2,7 @@ require 'whirled_peas/settings/box_settings'
2
2
  require 'whirled_peas/settings/graph_settings'
3
3
  require 'whirled_peas/settings/grid_settings'
4
4
  require 'whirled_peas/settings/text_settings'
5
+ require 'whirled_peas/settings/theme_library'
5
6
 
6
7
  require_relative 'box_painter'
7
8
  require_relative 'graph_painter'
@@ -25,8 +26,10 @@ module WhirledPeas
25
26
  "Element-#{@counter}"
26
27
  end
27
28
 
28
- def self.build
29
- settings = Settings::BoxSettings.new
29
+ def self.build(theme_name=nil, &block)
30
+ theme_name ||= Settings::ThemeLibrary.default_name
31
+ theme = Settings::ThemeLibrary.get(theme_name)
32
+ settings = Settings::BoxSettings.new(theme)
30
33
  template = BoxPainter.new('TEMPLATE', settings)
31
34
  composer = Composer.new(template)
32
35
  value = yield composer, settings
@@ -68,6 +71,10 @@ module WhirledPeas
68
71
  painter.add_child(child)
69
72
  end
70
73
 
74
+ def add_component(component)
75
+ component.compose(self, settings)
76
+ end
77
+
71
78
  def add_box(name=self.class.next_name, &block)
72
79
  child_settings = Settings::BoxSettings.inherit(painter.settings)
73
80
  child = BoxPainter.new(name, child_settings)