whirled_peas 0.5.0 → 0.9.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 (291) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +1 -0
  4. data/CHANGELOG.md +31 -0
  5. data/README.md +748 -137
  6. data/Rakefile +4 -32
  7. data/bin/easing +33 -0
  8. data/bin/reset_cursor +11 -0
  9. data/bin/screen_test +68 -0
  10. data/examples/graph.rb +54 -0
  11. data/examples/intro.rb +52 -0
  12. data/examples/scrolling.rb +54 -0
  13. data/lib/whirled_peas.rb +4 -12
  14. data/lib/whirled_peas/animator.rb +5 -0
  15. data/lib/whirled_peas/animator/debug_consumer.rb +17 -0
  16. data/lib/whirled_peas/animator/easing.rb +72 -0
  17. data/lib/whirled_peas/animator/frame.rb +5 -0
  18. data/lib/whirled_peas/animator/frameset.rb +33 -0
  19. data/lib/whirled_peas/animator/producer.rb +35 -0
  20. data/lib/whirled_peas/animator/renderer_consumer.rb +31 -0
  21. data/lib/whirled_peas/command.rb +5 -0
  22. data/lib/whirled_peas/command/base.rb +86 -0
  23. data/lib/whirled_peas/command/config_command.rb +44 -0
  24. data/lib/whirled_peas/command/debug.rb +21 -0
  25. data/lib/whirled_peas/command/fonts.rb +22 -0
  26. data/lib/whirled_peas/command/frame_command.rb +34 -0
  27. data/lib/whirled_peas/command/frames.rb +24 -0
  28. data/lib/whirled_peas/command/help.rb +38 -0
  29. data/lib/whirled_peas/command/play.rb +108 -0
  30. data/lib/whirled_peas/command/record.rb +57 -0
  31. data/lib/whirled_peas/command/still.rb +29 -0
  32. data/lib/whirled_peas/command_line.rb +22 -220
  33. data/lib/whirled_peas/config.rb +56 -6
  34. data/lib/whirled_peas/device.rb +5 -0
  35. data/lib/whirled_peas/device/null_device.rb +8 -0
  36. data/lib/whirled_peas/device/output_file.rb +19 -0
  37. data/lib/whirled_peas/device/screen.rb +26 -0
  38. data/lib/whirled_peas/graphics.rb +14 -0
  39. data/lib/whirled_peas/graphics/box_painter.rb +48 -47
  40. data/lib/whirled_peas/graphics/canvas.rb +22 -11
  41. data/lib/whirled_peas/graphics/composer.rb +98 -0
  42. data/lib/whirled_peas/graphics/container_coords.rb +24 -13
  43. data/lib/whirled_peas/graphics/container_dimensions.rb +37 -9
  44. data/lib/whirled_peas/graphics/container_painter.rb +283 -36
  45. data/lib/whirled_peas/graphics/content_dimensions.rb +19 -0
  46. data/lib/whirled_peas/graphics/content_painter.rb +20 -0
  47. data/lib/whirled_peas/graphics/debugger.rb +10 -1
  48. data/lib/whirled_peas/graphics/graph_dimensions.rb +12 -0
  49. data/lib/whirled_peas/graphics/graph_painter.rb +95 -0
  50. data/lib/whirled_peas/graphics/grid_painter.rb +25 -15
  51. data/lib/whirled_peas/graphics/mock_screen.rb +1 -1
  52. data/lib/whirled_peas/graphics/painter.rb +15 -6
  53. data/lib/whirled_peas/graphics/renderer.rb +13 -30
  54. data/lib/whirled_peas/graphics/text_painter.rb +11 -13
  55. data/lib/whirled_peas/settings/alignment.rb +24 -0
  56. data/lib/whirled_peas/settings/bg_color.rb +2 -0
  57. data/lib/whirled_peas/settings/border.rb +16 -16
  58. data/lib/whirled_peas/settings/color.rb +13 -14
  59. data/lib/whirled_peas/settings/container_settings.rb +133 -40
  60. data/lib/whirled_peas/settings/debugger.rb +9 -0
  61. data/lib/whirled_peas/settings/display_flow.rb +13 -11
  62. data/lib/whirled_peas/settings/element_settings.rb +8 -3
  63. data/lib/whirled_peas/settings/graph_settings.rb +21 -0
  64. data/lib/whirled_peas/settings/grid_settings.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 +34 -0
  68. data/lib/whirled_peas/settings/text_color.rb +2 -0
  69. data/lib/whirled_peas/settings/vert_alignment.rb +24 -0
  70. data/lib/whirled_peas/utils/ansi.rb +13 -0
  71. data/lib/whirled_peas/utils/file_handler.rb +57 -0
  72. data/lib/whirled_peas/utils/title_font.rb +1 -1
  73. data/lib/whirled_peas/version.rb +1 -1
  74. data/screen_test/{rendered/elements → elements}/box.frame +1 -1
  75. data/screen_test/{rendered/elements → elements}/box.rb +0 -0
  76. data/screen_test/elements/graph.frame +1 -0
  77. data/screen_test/elements/graph.rb +12 -0
  78. data/screen_test/elements/grid.frame +1 -0
  79. data/screen_test/{rendered/elements → elements}/grid.rb +0 -0
  80. data/screen_test/elements/screen_overflow_x.frame +1 -0
  81. data/screen_test/{rendered/elements/screen_overflow.rb → elements/screen_overflow_x.rb} +0 -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/{rendered/elements → elements}/text.rb +0 -0
  86. data/screen_test/elements/text_multiline.frame +1 -0
  87. data/screen_test/{rendered/elements → elements}/text_multiline.rb +0 -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/{rendered/settings/align/box.rb → settings/align/box_center.rb} +5 -4
  94. data/screen_test/settings/align/box_default.frame +1 -0
  95. data/screen_test/{rendered/settings/align/grid.rb → settings/align/box_default.rb} +6 -6
  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/{rendered/settings/width/overflow_box_t2b.rb → settings/ansi/bold.rb} +4 -5
  118. data/screen_test/{rendered/settings → settings}/ansi/color.frame +1 -1
  119. data/screen_test/{rendered/settings → settings}/ansi/color.rb +0 -0
  120. data/screen_test/settings/ansi/underline.frame +1 -0
  121. data/screen_test/{rendered/settings → settings}/ansi/underline.rb +4 -5
  122. data/screen_test/{rendered/settings → settings}/border.frame +1 -1
  123. data/screen_test/{rendered/settings → settings}/border.rb +1 -1
  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/{rendered/settings/margin.rb → settings/flow/grid_l2r.rb} +4 -4
  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/{rendered/settings → settings}/height/box.rb +0 -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/{rendered/settings → settings}/height/grid.rb +0 -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/{rendered/settings → settings}/height/overflow_grid.rb +0 -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/{rendered/settings → settings}/position/box_left.rb +2 -2
  160. data/screen_test/settings/position/box_left_negative.frame +1 -0
  161. data/screen_test/{rendered/settings → settings}/position/box_left_negative.rb +2 -2
  162. data/screen_test/settings/position/box_top.frame +1 -0
  163. data/screen_test/{rendered/settings → settings}/position/box_top.rb +1 -1
  164. data/screen_test/settings/position/box_top_negative.frame +1 -0
  165. data/screen_test/{rendered/settings → settings}/position/box_top_negative.rb +2 -2
  166. data/screen_test/settings/position/grid_left.frame +1 -0
  167. data/screen_test/{rendered/settings → settings}/position/grid_left.rb +1 -1
  168. data/screen_test/settings/position/grid_left_negative.frame +1 -0
  169. data/screen_test/{rendered/settings → settings}/position/grid_left_negative.rb +1 -1
  170. data/screen_test/settings/position/grid_top.frame +1 -0
  171. data/screen_test/{rendered/settings → settings}/position/grid_top.rb +1 -1
  172. data/screen_test/settings/position/grid_top_negative.frame +1 -0
  173. data/screen_test/{rendered/settings → settings}/position/grid_top_negative.rb +1 -1
  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/{rendered/settings → settings}/title_font.rb +1 -1
  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/{rendered/settings/width/box.rb → settings/width/box_default.rb} +3 -2
  210. data/screen_test/settings/width/grid.frame +1 -0
  211. data/screen_test/{rendered/settings → settings}/width/grid.rb +2 -2
  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/{rendered/settings → settings}/width/overflow_grid.rb +0 -0
  224. data/tools/whirled_peas/tools/screen_tester.rb +285 -0
  225. metadata +192 -98
  226. data/bin/debug +0 -35
  227. data/lib/whirled_peas/debugger.rb +0 -80
  228. data/lib/whirled_peas/frame.rb +0 -6
  229. data/lib/whirled_peas/frame/consumer.rb +0 -30
  230. data/lib/whirled_peas/frame/debug_consumer.rb +0 -30
  231. data/lib/whirled_peas/frame/event_loop.rb +0 -90
  232. data/lib/whirled_peas/frame/producer.rb +0 -67
  233. data/lib/whirled_peas/graphics/screen.rb +0 -65
  234. data/lib/whirled_peas/graphics/text_dimensions.rb +0 -15
  235. data/lib/whirled_peas/settings/text_align.rb +0 -19
  236. data/lib/whirled_peas/template.rb +0 -5
  237. data/lib/whirled_peas/template/box_element.rb +0 -8
  238. data/lib/whirled_peas/template/composer.rb +0 -68
  239. data/lib/whirled_peas/template/container.rb +0 -28
  240. data/lib/whirled_peas/template/debugger.rb +0 -34
  241. data/lib/whirled_peas/template/element.rb +0 -13
  242. data/lib/whirled_peas/template/grid_element.rb +0 -8
  243. data/lib/whirled_peas/template/text_element.rb +0 -24
  244. data/screen_test/rendered/elements/grid.frame +0 -1
  245. data/screen_test/rendered/elements/text.frame +0 -1
  246. data/screen_test/rendered/elements/text_multiline.frame +0 -1
  247. data/screen_test/rendered/settings/align/box.frame +0 -1
  248. data/screen_test/rendered/settings/align/children_center.frame +0 -1
  249. data/screen_test/rendered/settings/align/children_center.rb +0 -13
  250. data/screen_test/rendered/settings/align/children_left.frame +0 -1
  251. data/screen_test/rendered/settings/align/children_left.rb +0 -13
  252. data/screen_test/rendered/settings/align/children_right.frame +0 -1
  253. data/screen_test/rendered/settings/align/children_right.rb +0 -13
  254. data/screen_test/rendered/settings/align/grid.frame +0 -1
  255. data/screen_test/rendered/settings/ansi/bold.frame +0 -1
  256. data/screen_test/rendered/settings/ansi/bold.rb +0 -15
  257. data/screen_test/rendered/settings/ansi/underline.frame +0 -1
  258. data/screen_test/rendered/settings/flow/l2r.frame +0 -1
  259. data/screen_test/rendered/settings/flow/l2r.rb +0 -24
  260. data/screen_test/rendered/settings/flow/t2b.frame +0 -1
  261. data/screen_test/rendered/settings/flow/t2b.rb +0 -24
  262. data/screen_test/rendered/settings/height/box.frame +0 -1
  263. data/screen_test/rendered/settings/height/grid.frame +0 -1
  264. data/screen_test/rendered/settings/height/overflow_box.frame +0 -1
  265. data/screen_test/rendered/settings/height/overflow_box.rb +0 -13
  266. data/screen_test/rendered/settings/height/overflow_box_l2r.frame +0 -1
  267. data/screen_test/rendered/settings/height/overflow_box_l2r.rb +0 -15
  268. data/screen_test/rendered/settings/height/overflow_box_t2b.frame +0 -1
  269. data/screen_test/rendered/settings/height/overflow_box_t2b.rb +0 -14
  270. data/screen_test/rendered/settings/height/overflow_grid.frame +0 -1
  271. data/screen_test/rendered/settings/margin.frame +0 -1
  272. data/screen_test/rendered/settings/padding.frame +0 -1
  273. data/screen_test/rendered/settings/padding.rb +0 -11
  274. data/screen_test/rendered/settings/position/box_left.frame +0 -1
  275. data/screen_test/rendered/settings/position/box_left_negative.frame +0 -1
  276. data/screen_test/rendered/settings/position/box_top.frame +0 -1
  277. data/screen_test/rendered/settings/position/box_top_negative.frame +0 -1
  278. data/screen_test/rendered/settings/position/grid_left.frame +0 -1
  279. data/screen_test/rendered/settings/position/grid_left_negative.frame +0 -1
  280. data/screen_test/rendered/settings/position/grid_top.frame +0 -1
  281. data/screen_test/rendered/settings/position/grid_top_negative.frame +0 -1
  282. data/screen_test/rendered/settings/title_font.frame +0 -1
  283. data/screen_test/rendered/settings/width/box.frame +0 -1
  284. data/screen_test/rendered/settings/width/grid.frame +0 -1
  285. data/screen_test/rendered/settings/width/overflow_box.frame +0 -1
  286. data/screen_test/rendered/settings/width/overflow_box.rb +0 -11
  287. data/screen_test/rendered/settings/width/overflow_box_l2r.frame +0 -1
  288. data/screen_test/rendered/settings/width/overflow_box_l2r.rb +0 -14
  289. data/screen_test/rendered/settings/width/overflow_box_t2b.frame +0 -1
  290. data/screen_test/rendered/settings/width/overflow_grid.frame +0 -1
  291. data/screen_test/screen_tester.rb +0 -191
@@ -0,0 +1,26 @@
1
+ require 'highline'
2
+
3
+ module WhirledPeas
4
+ module Device
5
+ class Screen
6
+ def initialize(refresh_rate, output: STDOUT)
7
+ @refresh_rate = refresh_rate
8
+ @output = output
9
+ end
10
+
11
+ def handle_renders(renders)
12
+ renders.each do |strokes|
13
+ frame_at = Time.now
14
+ output.print(strokes)
15
+ output.flush
16
+ next_frame_at = frame_at + 1.0 / refresh_rate
17
+ sleep([0, next_frame_at - Time.now].max)
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :refresh_rate, :output
24
+ end
25
+ end
26
+ end
@@ -1,5 +1,19 @@
1
1
  module WhirledPeas
2
2
  module Graphics
3
+ class << self
4
+ attr_accessor :debug
5
+
6
+ def debugger(string_or_proc)
7
+ return unless @debug
8
+ @debugger ||= Logger.new(STDOUT, level: Logger::DEBUG)
9
+ if string_or_proc.is_a?(Proc)
10
+ string = string_or_proc.call
11
+ else
12
+ string = string_or_proc
13
+ end
14
+ @debugger.debug(string)
15
+ end
16
+ end
3
17
  end
4
18
  private_constant :Graphics
5
19
  end
@@ -4,13 +4,20 @@ require_relative 'container_dimensions'
4
4
  module WhirledPeas
5
5
  module Graphics
6
6
  class BoxPainter < ContainerPainter
7
- def paint(canvas, &block)
7
+ def paint(canvas, left, top, &block)
8
8
  super
9
- return unless canvas.writable?
10
- if element.settings.horizontal_flow?
11
- paint_horizontally(canvas, &block)
9
+ canvas_coords = coords(left, top)
10
+ content_canvas = canvas.child(
11
+ canvas_coords.content_left,
12
+ canvas_coords.content_top,
13
+ dimensions.content_width,
14
+ dimensions.content_height
15
+ )
16
+ return unless content_canvas.writable?
17
+ if settings.horizontal_flow?
18
+ paint_horizontally(content_canvas, canvas_coords, &block)
12
19
  else
13
- paint_vertically(canvas, &block)
20
+ paint_vertically(content_canvas, canvas_coords, &block)
14
21
  end
15
22
  end
16
23
 
@@ -37,61 +44,55 @@ module WhirledPeas
37
44
  end
38
45
  end
39
46
 
47
+ def each_child(&block)
48
+ if settings.reverse_flow?
49
+ children.reverse.each(&block)
50
+ else
51
+ super
52
+ end
53
+ end
54
+
40
55
  private
41
56
 
42
- def paint_horizontally(canvas, &block)
43
- stroke_top = coords(canvas).content_top
44
- stroke_left = coords(canvas).content_left
45
- total_child_width = 0
46
- each_child { |c| total_child_width += c.dimensions.outer_width }
47
- if settings.align_center?
48
- stroke_left += (dimensions.content_width - total_child_width) / 2
49
- elsif settings.align_right?
50
- stroke_left += dimensions.content_width - total_child_width
51
- end
52
- given_width = 0
57
+ def paint_horizontally(canvas, canvas_coords, &block)
58
+ stroke_left = canvas_coords.content_left
59
+ stroke_top = canvas_coords.content_top
60
+ children_width = 0
61
+ each_child { |c| children_width += c.dimensions.outer_width }
62
+ left_offset, spacing_offset = horiz_justify_offset(children_width)
63
+ stroke_left += left_offset
53
64
  each_child do |child|
54
- child_width = [
55
- child.dimensions.outer_width,
56
- dimensions.content_width - given_width
57
- ].min
65
+ top_offset, _ = vert_justify_offset(child.dimensions.outer_height)
66
+ child_width = child.dimensions.outer_width
58
67
  child_canvas = canvas.child(
59
- stroke_left + given_width,
60
- stroke_top,
68
+ stroke_left,
69
+ stroke_top + top_offset,
61
70
  child_width,
62
- [dimensions.content_height, child.dimensions.outer_height].min
71
+ child.dimensions.outer_height
63
72
  )
64
- child.paint(child_canvas, &block)
65
- given_width += child_width
66
- break if given_width == dimensions.content_width
73
+ child.paint(child_canvas, stroke_left, stroke_top + top_offset, &block)
74
+ stroke_left += child_width + spacing_offset
67
75
  end
68
76
  end
69
77
 
70
- def paint_vertically(canvas, &block)
71
- stroke_top = coords(canvas).content_top
72
- stroke_left = coords(canvas).content_left
73
- given_height = 0
78
+ def paint_vertically(canvas, canvas_coords, &block)
79
+ stroke_left = canvas_coords.content_left
80
+ stroke_top = canvas_coords.content_top
81
+ children_height = 0
82
+ each_child { |c| children_height += c.dimensions.outer_height }
83
+ top_offset, spacing_offset = vert_justify_offset(children_height)
84
+ stroke_top += top_offset
74
85
  each_child do |child|
75
- if settings.align_center?
76
- justify_offset = (dimensions.content_width - child.dimensions.outer_width) / 2
77
- elsif settings.align_right?
78
- justify_offset = dimensions.content_width - child.dimensions.outer_width
79
- else
80
- justify_offset = 0
81
- end
82
- child_height = [
83
- child.dimensions.outer_height,
84
- dimensions.content_height - given_height
85
- ].min
86
+ left_offset, _ = horiz_justify_offset(child.dimensions.outer_width)
87
+ child_height = child.dimensions.outer_height
86
88
  child_canvas = canvas.child(
87
- stroke_left + justify_offset,
88
- stroke_top + given_height,
89
- [dimensions.content_width, child.dimensions.outer_width].min,
89
+ stroke_left + left_offset,
90
+ stroke_top ,
91
+ child.dimensions.outer_width,
90
92
  child_height
91
93
  )
92
- child.paint(child_canvas, &block)
93
- given_height += child_height
94
- break if given_height == dimensions.content_height
94
+ child.paint(child_canvas, stroke_left + left_offset, stroke_top, &block)
95
+ stroke_top += child_height + spacing_offset
95
96
  end
96
97
  end
97
98
  end
@@ -4,28 +4,29 @@ module WhirledPeas
4
4
  module Graphics
5
5
  # Canvas represent the area of the screen a painter can paint on.
6
6
  class Canvas
7
- attr_reader :left, :top, :width, :height, :start_left, :start_top
7
+ attr_reader :left, :top, :width, :height
8
8
 
9
9
  def self.unwritable
10
- new(-1, -1, 0, 0, -1, -1)
10
+ new(-1, -1, 0, 0)
11
11
  end
12
12
 
13
- def initialize(left, top, width, height, start_left, start_top)
13
+ def initialize(left, top, width, height)
14
14
  @left = left
15
15
  @top = top
16
16
  @width = width
17
17
  @height = height
18
- @start_left = start_left
19
- @start_top = start_top
20
18
  end
21
19
 
22
20
  def writable?
23
21
  width > 0 || height > 0
24
22
  end
25
23
 
26
- def child(start_left, start_top, child_width, child_height)
27
- child_left = start_left
28
- child_top = start_top
24
+ def child(child_left, child_top, child_width, child_height)
25
+ Graphics.debugger(
26
+ proc do
27
+ "Create child: #{self.inspect}.child(left=#{child_left}, top=#{child_top}, width=#{child_width}, height=#{child_height})"
28
+ end
29
+ )
29
30
  if child_left >= left + width
30
31
  self.class.unwritable
31
32
  elsif child_left + child_width <= left
@@ -45,20 +46,25 @@ module WhirledPeas
45
46
  child_top = top
46
47
  end
47
48
  child_height = [height - (child_top - top), child_height].min
48
- self.class.new(
49
+ child_canvas = self.class.new(
49
50
  child_left,
50
51
  child_top,
51
52
  child_width,
52
53
  child_height,
53
- start_left,
54
- start_top
55
54
  )
55
+ Graphics.debugger(proc { " -> #{child_canvas.inspect}" })
56
+ child_canvas
56
57
  end
57
58
  end
58
59
 
59
60
  # Yields a single line of formatted characters positioned on the canvas,
60
61
  # verifying only characters within the canvas are included.
61
62
  def stroke(stroke_left, stroke_top, raw, formatting=[], &block)
63
+ Graphics.debugger(
64
+ proc do
65
+ "Stroke: #{self.inspect}.stroke(left=#{stroke_left}, top=#{stroke_top}, length=#{raw.length})"
66
+ end
67
+ )
62
68
  if stroke_left >= left + width
63
69
  # The stroke starts to the right of the canvas
64
70
  fstring = Utils::FormattedString.blank
@@ -88,6 +94,11 @@ module WhirledPeas
88
94
  end_index = start_index + visible_length - 1
89
95
  fstring = Utils::FormattedString.new(raw[start_index..end_index], formatting)
90
96
  end
97
+ Graphics.debugger(
98
+ proc do
99
+ " -> Stroke(left=#{stroke_left}, top=#{stroke_top}, length=#{fstring.length})"
100
+ end
101
+ )
91
102
  yield stroke_left, stroke_top, fstring
92
103
  end
93
104
 
@@ -0,0 +1,98 @@
1
+ require 'whirled_peas/settings/box_settings'
2
+ require 'whirled_peas/settings/graph_settings'
3
+ require 'whirled_peas/settings/grid_settings'
4
+ require 'whirled_peas/settings/text_settings'
5
+
6
+ require_relative 'box_painter'
7
+ require_relative 'graph_painter'
8
+ require_relative 'grid_painter'
9
+ require_relative 'text_painter'
10
+
11
+ module WhirledPeas
12
+ module Graphics
13
+ class Composer
14
+ # List of classes that convert nicely to a string
15
+ STRINGALBE_CLASSES = [FalseClass, Float, Integer, NilClass, String, Symbol, TrueClass]
16
+ private_constant :STRINGALBE_CLASSES
17
+
18
+ def self.stringable?(value)
19
+ STRINGALBE_CLASSES.include?(value.class)
20
+ end
21
+
22
+ def self.next_name
23
+ @counter ||= 0
24
+ @counter += 1
25
+ "Element-#{@counter}"
26
+ end
27
+
28
+ def self.build
29
+ settings = Settings::BoxSettings.new
30
+ template = BoxPainter.new('TEMPLATE', settings)
31
+ composer = Composer.new(template)
32
+ value = yield composer, settings
33
+ if !template.children? && stringable?(value)
34
+ composer.add_text { value.to_s }
35
+ end
36
+ template
37
+ end
38
+
39
+ attr_reader :painter
40
+
41
+ def initialize(painter)
42
+ @painter = painter
43
+ end
44
+
45
+ def add_text(name=self.class.next_name, &block)
46
+ child_settings = Settings::TextSettings.inherit(painter.settings)
47
+ child = TextPainter.new(name, child_settings)
48
+ # TextPainters are not composable, so yield nil
49
+ content = yield nil, child_settings
50
+ child_settings.validate!
51
+ unless self.class.stringable?(content)
52
+ raise ArgumentError, "Unsupported type for text: #{content.class}"
53
+ end
54
+ child.content = content.to_s
55
+ painter.add_child(child)
56
+ end
57
+
58
+ def add_graph(name=self.class.next_name, &block)
59
+ child_settings = Settings::GraphSettings.inherit(painter.settings)
60
+ child = GraphPainter.new(name, child_settings)
61
+ # GraphPainters are not composable, so yield nil
62
+ content = yield nil, child_settings
63
+ child_settings.validate!
64
+ unless content.is_a?(Array) && content.length > 0
65
+ raise ArgumentError, 'Graphs require a non-empty array as the content'
66
+ end
67
+ child.content = content
68
+ painter.add_child(child)
69
+ end
70
+
71
+ def add_box(name=self.class.next_name, &block)
72
+ child_settings = Settings::BoxSettings.inherit(painter.settings)
73
+ child = BoxPainter.new(name, child_settings)
74
+ composer = self.class.new(child)
75
+ value = yield composer, child.settings
76
+ child_settings.validate!
77
+ painter.add_child(child)
78
+ if !child.children? && self.class.stringable?(value)
79
+ composer.add_text("#{name}-Text") { value.to_s }
80
+ end
81
+ end
82
+
83
+ def add_grid(name=self.class.next_name, &block)
84
+ child_settings = Settings::GridSettings.inherit(painter.settings)
85
+ child = GridPainter.new(name, child_settings)
86
+ composer = self.class.new(child)
87
+ values = yield composer, child.settings
88
+ child_settings.validate!
89
+ painter.add_child(child)
90
+ if !child.children? && values.is_a?(Array)
91
+ values.each.with_index do |value, index|
92
+ composer.add_text("#{name}-Text-#{index}") { value.to_s }
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -1,18 +1,19 @@
1
1
  module WhirledPeas
2
2
  module Graphics
3
3
  class ContainerCoords
4
- def initialize(canvas, dimensions, settings)
5
- @canvas = canvas
4
+ def initialize(dimensions, settings, start_left, start_top)
6
5
  @dimensions = dimensions
7
6
  @settings = settings
7
+ @start_left = start_left
8
+ @start_top = start_top
8
9
  end
9
10
 
10
11
  def left
11
- canvas.start_left + settings.position.left
12
+ start_left + settings.position.left
12
13
  end
13
14
 
14
15
  def top
15
- canvas.start_top + settings.position.top
16
+ start_top + settings.position.top
16
17
  end
17
18
 
18
19
  def border_left
@@ -32,30 +33,40 @@ module WhirledPeas
32
33
  end
33
34
 
34
35
  def content_left(col_index=0)
35
- padding_left + settings.padding.left + col_index * grid_width(true)
36
+ padding_left + settings.padding.left + col_index * grid_width
36
37
  end
37
38
 
38
39
  def content_top(row_index=0)
39
- padding_top + settings.padding.top + row_index * grid_height(true)
40
+ padding_top + settings.padding.top + row_index * grid_height
40
41
  end
41
42
 
42
- def grid_width(include_border)
43
- (include_border && settings.border.inner_vert? ? 1 : 0) +
44
- settings.padding.left +
43
+ def inner_grid_width
44
+ settings.padding.left +
45
45
  dimensions.content_width +
46
46
  settings.padding.right
47
47
  end
48
48
 
49
- def grid_height(include_border)
50
- (include_border && settings.border.inner_horiz? ? 1 : 0) +
51
- settings.padding.top +
49
+ def grid_width
50
+ (settings.border.inner_vert? ? 1 : 0) +
51
+ inner_grid_width +
52
+ (settings.scrollbar.vert? ? 1 : 0)
53
+ end
54
+
55
+ def inner_grid_height
56
+ settings.padding.top +
52
57
  dimensions.content_height +
53
58
  settings.padding.bottom
54
59
  end
55
60
 
61
+ def grid_height
62
+ (settings.border.inner_horiz? ? 1 : 0) +
63
+ inner_grid_height +
64
+ (settings.scrollbar.horiz? ? 1 : 0)
65
+ end
66
+
56
67
  private
57
68
 
58
- attr_reader :canvas, :settings, :dimensions
69
+ attr_reader :settings, :dimensions, :start_left, :start_top
59
70
  end
60
71
  end
61
72
  end
@@ -1,34 +1,50 @@
1
1
  module WhirledPeas
2
2
  module Graphics
3
3
  class ContainerDimensions
4
- attr_reader :content_width, :content_height, :num_cols, :num_rows
4
+ attr_reader :children_width, :children_height, :num_cols, :num_rows
5
5
 
6
6
  def initialize(settings, content_width, content_height, num_cols=1, num_rows=1)
7
- @content_width = settings.width || content_width
8
- @content_height = settings.height || content_height
7
+ @orig_content_width = content_width
8
+ @orig_content_height = content_height
9
+ @children_width = content_width
10
+ @children_height = content_height
9
11
  @num_cols = num_cols
10
12
  @num_rows = num_rows
11
13
  @settings = settings
12
14
  end
13
15
 
16
+ def content_width
17
+ return orig_content_width unless settings.width
18
+ if settings.border_sizing?
19
+ settings.width - outer_border_width - scrollbar_width - padding_width
20
+ else
21
+ settings.width
22
+ end
23
+ end
24
+
25
+ def content_height
26
+ return orig_content_height unless settings.height
27
+ if settings.border_sizing?
28
+ settings.height - outer_border_height - scrollbar_height - padding_height
29
+ else
30
+ settings.height
31
+ end
32
+ end
33
+
14
34
  def outer_width
15
35
  @outer_width ||= margin_width +
16
36
  outer_border_width +
17
- num_cols * (padding_width + content_width) +
37
+ num_cols * (padding_width + content_width + scrollbar_width) +
18
38
  (num_cols - 1) * inner_border_width
19
39
  end
20
40
 
21
41
  def outer_height
22
42
  @outer_height ||= margin_height +
23
43
  outer_border_height +
24
- num_rows * (padding_height + content_height) +
44
+ num_rows * (padding_height + content_height + scrollbar_height) +
25
45
  (num_rows - 1) * inner_border_height
26
46
  end
27
47
 
28
- private
29
-
30
- attr_reader :settings
31
-
32
48
  def margin_width
33
49
  settings.margin.left + settings.margin.right
34
50
  end
@@ -60,6 +76,18 @@ module WhirledPeas
60
76
  def padding_height
61
77
  settings.padding.top + settings.padding.bottom
62
78
  end
79
+
80
+ def scrollbar_width
81
+ settings.scrollbar.vert? ? 1 : 0
82
+ end
83
+
84
+ def scrollbar_height
85
+ settings.scrollbar.horiz? ? 1 : 0
86
+ end
87
+
88
+ private
89
+
90
+ attr_reader :settings, :orig_content_width, :orig_content_height
63
91
  end
64
92
  end
65
93
  end