whirled_peas 0.9.1 → 0.13.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 (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
@@ -9,11 +9,11 @@ module WhirledPeas
9
9
  end
10
10
 
11
11
  def left
12
- start_left + settings.position.left
12
+ start_left
13
13
  end
14
14
 
15
15
  def top
16
- start_top + settings.position.top
16
+ start_top
17
17
  end
18
18
 
19
19
  def border_left
@@ -33,35 +33,33 @@ module WhirledPeas
33
33
  end
34
34
 
35
35
  def content_left(col_index=0)
36
- padding_left + settings.padding.left + col_index * grid_width
36
+ padding_left + settings.padding.left + col_index * dimensions.grid_width
37
37
  end
38
38
 
39
- def content_top(row_index=0)
40
- padding_top + settings.padding.top + row_index * grid_height
41
- end
42
-
43
- def inner_grid_width
44
- settings.padding.left +
45
- dimensions.content_width +
46
- settings.padding.right
39
+ def offset_content_left(col_index=0)
40
+ if settings.content_start.left
41
+ content_left(col_index) + settings.content_start.left
42
+ elsif settings.content_start.right
43
+ left_offset = dimensions.content_width - dimensions.children_width
44
+ content_left(col_index) + left_offset - settings.content_start.right
45
+ else
46
+ content_left(col_index)
47
+ end
47
48
  end
48
49
 
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 +
57
- dimensions.content_height +
58
- settings.padding.bottom
50
+ def content_top(row_index=0)
51
+ padding_top + settings.padding.top + row_index * dimensions.grid_height
59
52
  end
60
53
 
61
- def grid_height
62
- (settings.border.inner_horiz? ? 1 : 0) +
63
- inner_grid_height +
64
- (settings.scrollbar.horiz? ? 1 : 0)
54
+ def offset_content_top(row_index=0)
55
+ if settings.content_start.top
56
+ content_top(row_index) + settings.content_start.top
57
+ elsif settings.content_start.bottom
58
+ top_offset = dimensions.content_height - dimensions.children_height
59
+ content_top(row_index) + top_offset - settings.content_start.bottom
60
+ else
61
+ content_top(row_index)
62
+ end
65
63
  end
66
64
 
67
65
  private
@@ -31,6 +31,30 @@ module WhirledPeas
31
31
  end
32
32
  end
33
33
 
34
+ def inner_grid_width
35
+ settings.padding.left +
36
+ content_width +
37
+ settings.padding.right
38
+ end
39
+
40
+ def grid_width
41
+ (settings.border.inner_vert? ? 1 : 0) +
42
+ inner_grid_width +
43
+ (settings.scrollbar.vert? ? 1 : 0)
44
+ end
45
+
46
+ def inner_grid_height
47
+ settings.padding.top +
48
+ content_height +
49
+ settings.padding.bottom
50
+ end
51
+
52
+ def grid_height
53
+ (settings.border.inner_horiz? ? 1 : 0) +
54
+ inner_grid_height +
55
+ (settings.scrollbar.horiz? ? 1 : 0)
56
+ end
57
+
34
58
  def outer_width
35
59
  @outer_width ||= margin_width +
36
60
  outer_border_width +
@@ -2,6 +2,7 @@ require 'whirled_peas/utils/formatted_string'
2
2
 
3
3
  require_relative 'container_coords'
4
4
  require_relative 'painter'
5
+ require_relative 'scrollbar_helper'
5
6
 
6
7
  module WhirledPeas
7
8
  module Graphics
@@ -34,11 +35,17 @@ module WhirledPeas
34
35
 
35
36
  # Paint the top border if the settings call for it
36
37
  if settings.border.top?
37
- canvas.stroke(stroke_left, stroke_top, top_border_stroke(canvas_coords), formatting, &block)
38
+ canvas.stroke(stroke_left, stroke_top, top_border_stroke, formatting, &block)
38
39
  stroke_top += 1
39
40
  end
40
41
  # Precalculate the middle border container grids with more than 1 row
41
- middle_border = dimensions.num_rows > 1 ? middle_border_stroke(canvas_coords) : ''
42
+ middle_border = dimensions.num_rows > 1 ? middle_border_stroke : ''
43
+
44
+ vert_scrollbar = settings.scrollbar.vert? ? ScrollbarHelper.vert(
45
+ dimensions.children_height + dimensions.padding_height,
46
+ dimensions.inner_grid_height,
47
+ canvas_coords.content_top - canvas_coords.offset_content_top,
48
+ ) : []
42
49
 
43
50
  # Paint each grid row by row
44
51
  dimensions.num_rows.times do |row_num|
@@ -52,8 +59,9 @@ module WhirledPeas
52
59
 
53
60
  # Paint the interior of each row (horizontal borders, veritical scroll bar and
54
61
  # background color for the padding and content area)
55
- canvas_coords.inner_grid_height.times do |row_within_cell|
56
- canvas.stroke(stroke_left, stroke_top, content_line_stroke(canvas_coords, row_within_cell), formatting, &block)
62
+ dimensions.inner_grid_height.times do |row_within_cell|
63
+ content_line = content_line_stroke(row_within_cell, vert_scrollbar)
64
+ canvas.stroke(stroke_left, stroke_top, content_line, formatting, &block)
57
65
  stroke_top += 1
58
66
  end
59
67
 
@@ -66,7 +74,7 @@ module WhirledPeas
66
74
 
67
75
  # Paint the bottom border if the settings call for it
68
76
  if settings.border.bottom?
69
- canvas.stroke(stroke_left, stroke_top, bottom_border_stroke(canvas_coords), formatting, &block)
77
+ canvas.stroke(stroke_left, stroke_top, bottom_border_stroke, formatting, &block)
70
78
  stroke_top += 1
71
79
  end
72
80
  end
@@ -176,59 +184,49 @@ module WhirledPeas
176
184
  end
177
185
 
178
186
  # Return the stroke for the top border
179
- def top_border_stroke(canvas_coords)
187
+ def top_border_stroke
180
188
  line_stroke(
181
189
  settings.border.style.top_left,
182
190
  settings.border.style.top_junc,
183
191
  settings.border.style.top_right
184
192
  ) do
185
- settings.border.style.top_horiz * (canvas_coords.inner_grid_width + (settings.scrollbar.vert? ? 1 : 0))
193
+ settings.border.style.top_horiz * (dimensions.inner_grid_width + (settings.scrollbar.vert? ? 1 : 0))
186
194
  end
187
195
  end
188
196
 
189
197
  # Return the stroke for an inner horizontal border
190
- def middle_border_stroke(canvas_coords)
198
+ def middle_border_stroke
191
199
  line_stroke(
192
200
  settings.border.style.left_junc,
193
201
  settings.border.style.cross_junc,
194
202
  settings.border.style.right_junc
195
203
  ) do
196
- settings.border.style.middle_horiz * (canvas_coords.inner_grid_width + (settings.scrollbar.vert? ? 1 : 0))
204
+ settings.border.style.middle_horiz * (dimensions.inner_grid_width + (settings.scrollbar.vert? ? 1 : 0))
197
205
  end
198
206
  end
199
207
 
200
208
  # Return the stroke for the bottom border
201
- def bottom_border_stroke(canvas_coords)
209
+ def bottom_border_stroke
202
210
  line_stroke(
203
211
  settings.border.style.bottom_left,
204
212
  settings.border.style.bottom_junc,
205
213
  settings.border.style.bottom_right
206
214
  ) do
207
- settings.border.style.bottom_horiz * (canvas_coords.inner_grid_width + (settings.scrollbar.vert? ? 1 : 0))
215
+ settings.border.style.bottom_horiz * (dimensions.inner_grid_width + (settings.scrollbar.vert? ? 1 : 0))
208
216
  end
209
217
  end
210
218
 
211
219
  # Return the stroke for a grid row between any borders
212
- def content_line_stroke(canvas_coords, row_within_cell)
220
+ def content_line_stroke(row_within_cell, vert_scrollbar)
213
221
  line_stroke(
214
222
  settings.border.style.left_vert,
215
223
  settings.border.style.middle_vert,
216
224
  settings.border.style.right_vert,
217
225
  ) do
218
226
  if settings.scrollbar.vert?
219
- if dimensions.children_height <= canvas_coords.grid_height || children.first.settings.position.top > 0
220
- scrollbar_char = GUTTER
221
- else
222
- scrollbar_char = vert_scroll_char(
223
- dimensions.children_height + dimensions.padding_height,
224
- canvas_coords.inner_grid_height,
225
- -children.first.settings.position.top,
226
- row_within_cell
227
- )
228
- end
229
- PADDING * canvas_coords.inner_grid_width + scrollbar_char
227
+ PADDING * dimensions.inner_grid_width + vert_scrollbar[row_within_cell]
230
228
  else
231
- PADDING * canvas_coords.inner_grid_width
229
+ PADDING * dimensions.inner_grid_width
232
230
  end
233
231
  end
234
232
  end
@@ -240,121 +238,11 @@ module WhirledPeas
240
238
  settings.border.style.middle_vert,
241
239
  settings.border.style.right_vert,
242
240
  ) do
243
- canvas_coords.inner_grid_width.times.map do |col_within_cell|
244
- horiz_scroll_char(
245
- dimensions.children_width + dimensions.padding_width,
246
- canvas_coords.inner_grid_width,
247
- -children.first.settings.position.left,
248
- col_within_cell
249
- )
250
- end.join
251
- end
252
- end
253
-
254
- # Contants to paint scrollbars
255
- GUTTER = ' '
256
- HORIZONTAL = %w[▗ ▄ ▖]
257
- VERTICAL = %w[
258
-
259
-
260
-
261
- ]
262
-
263
- # Determine the character to paint the horizontal scroll bar with for the given column
264
- #
265
- # @see #scroll_char for more details
266
- def horiz_scroll_char(col_count, viewable_col_count, first_visible_col, curr_col)
267
- scroll_char(col_count, viewable_col_count, first_visible_col, curr_col, HORIZONTAL)
268
- end
269
-
270
- # Determine the character to paint the vertical scroll bar with for the given row
271
- #
272
- # @see #scroll_char for more details
273
- def vert_scroll_char(row_count, viewable_row_count, first_visible_row, curr_row)
274
- scroll_char(row_count, viewable_row_count, first_visible_row, curr_row, VERTICAL)
275
- end
276
-
277
- private
278
-
279
- # Determine which character to paint a for a scrollbar
280
- #
281
- # @param total_count [Integer] total number of rows/columns in the content
282
- # @param viewable_count [Integer] number of rows/columns visible in the viewport
283
- # @param first_visible [Integer] zero-based index of the first row/column that is visible
284
- # in the viewport
285
- # @param curr [Integer] zero-based index of the row/column (relative to the first visible
286
- # row/column) that the painted character is being requested for
287
- # @param chars [Array<String>] an array with three 1-character strings, the frist is the
288
- # "second half" scrollbar character, the second is the "full" scrollbar character, and
289
- # the third is the "first half" scrollbar character.
290
- def scroll_char(total_count, viewable_count, first_visible, curr, chars)
291
- return GUTTER unless total_count > 0 && viewable_count > 0
292
- # The scroll handle has the exact same relative size and position in the scroll gutter
293
- # that the viewable content has in the total content area. For example, a content area
294
- # that is 50 columns wide with a view port that is 20 columns wide might look like
295
- #
296
- # +---------1-----****2*********3******---4---------+
297
- # | * * |
298
- # | hidden * viewable * hidden |
299
- # | * * |
300
- # +---------1-----****2*********3******---4---------+
301
- #
302
- # The scoll gutter, would look like
303
- #
304
- # |......********.....|
305
- #
306
- # Scrolling all the way to the right results in
307
- #
308
- # +---------1---------2---------3*********4*********+
309
- # | * *
310
- # | hidden * viewable *
311
- # | * *
312
- # +---------1---------2---------3*********4*********+
313
- # |...........********|
314
- #
315
- # Returning to the first example, we can match up the arguments to this method to the
316
- # diagram
317
- #
318
- # total_count = 50
319
- # |<----------------------------------------------->|
320
- # | |
321
- # | veiwable_count = 20 |
322
- # | |<----------------->| |
323
- # ↓ ↓ ↓ ↓
324
- # +---------1-----****2*********3******---4---------+
325
- # | * * |
326
- # | hidden * viewable * hidden |
327
- # | * * |
328
- # +---------1-----****2*********3******---4---------+
329
- # |......****?***.....|
330
- # ↑ ↑
331
- # first_visible = 16 |
332
- # curr = 11
333
-
334
- # The first task of determining how much of the handle is visible in a row/column is to
335
- # calculate the range (as a precentage of the total) of viewable items
336
- viewable_start = first_visible.to_f / total_count
337
- viewable_end = (first_visible + viewable_count).to_f / total_count
338
-
339
- # Always use the same length for the scroll bar so it does not give an inchworm effect
340
- # as it scrolls along.
341
- #
342
- # Also, double the value now to get granularity for half width
343
- # scrollbar characters.
344
- scrollbar_length = ((2 * viewable_count ** 2).to_f / total_count).ceil
345
- scrollbar_start = ((2 * first_visible * viewable_count).to_f / total_count).floor
346
-
347
- first_half = (scrollbar_start...scrollbar_start + scrollbar_length).include?(2 * curr)
348
- second_half = (scrollbar_start...scrollbar_start + scrollbar_length).include?(2 * curr + 1)
349
-
350
- if first_half && second_half
351
- chars[1]
352
- elsif first_half
353
- chars[2]
354
- elsif second_half
355
- chars[0]
356
- else
357
- GUTTER
241
+ ScrollbarHelper.horiz(
242
+ dimensions.children_width + dimensions.padding_width,
243
+ dimensions.inner_grid_width,
244
+ canvas_coords.content_left - canvas_coords.offset_content_left
245
+ ).join
358
246
  end
359
247
  end
360
248
  end
@@ -15,16 +15,11 @@ module WhirledPeas
15
15
  "#{indent}* #{painter.class}(#{painter.name})",
16
16
  ]
17
17
  info << "#{indent + ' '}- Dimensions(#{dimensions})"
18
+ info << "#{indent + ' '}- Theme=#{painter.settings.theme.inspect}" if indent == ''
18
19
  info << "#{indent + ' '}- Settings"
19
20
  info << Settings::Debugger.new(painter.settings).debug(indent + ' ')
20
21
  if painter.is_a?(TextPainter)
21
- content = if painter.content.length > 1
22
- '<multiline>'
23
- elsif painter.content.first.length > 12
24
- "#{painter.content.first[0..9]}...".inspect
25
- else
26
- painter.content.first.inspect
27
- end
22
+ content = painter.content
28
23
  info << "#{indent + ' '}- Content(value=#{content})"
29
24
  elsif painter.is_a?(ContainerPainter)
30
25
  info << "#{indent + ' '}- Children"
@@ -5,6 +5,10 @@ require_relative 'content_painter'
5
5
  module WhirledPeas
6
6
  module Graphics
7
7
  class GraphPainter < ContentPainter
8
+ # The number of units along the Y-axis a single character can be divided into
9
+ Y_AXIS_SCALE = 2
10
+ private_constant :Y_AXIS_SCALE
11
+
8
12
  def paint(canvas, left, top, &block)
9
13
  axis_formatting = [*settings.axis_color, *settings.bg_color]
10
14
  plot_formatting = [*settings.color, *settings.bg_color]
@@ -26,8 +30,8 @@ module WhirledPeas
26
30
  min_y = 1.0 / 0
27
31
  max_y = -1.0 / 0
28
32
  if settings.width
29
- interpolated = inner_width.times.map do |i|
30
- x = (i * (content.length - 1).to_f / inner_width).floor
33
+ interpolated = (inner_width + 1).times.map do |i|
34
+ x = (i * (content.length - 1).to_f / (inner_width + 1)).floor
31
35
  max_y = content[x] if content[x] > max_y
32
36
  min_y = content[x] if content[x] < min_y
33
37
  content[x]
@@ -39,31 +43,34 @@ module WhirledPeas
39
43
  min_y = y if y < min_y
40
44
  end
41
45
  end
46
+ if min_y == max_y
47
+ min_y -= 1
48
+ max_y += 1
49
+ end
42
50
  scaled = interpolated.map do |y|
43
- (2 * inner_height * (y - min_y).to_f / (max_y - min_y)).floor
51
+ inner_height * (y - min_y).to_f / (max_y - min_y)
44
52
  end
53
+
45
54
  @plot_lines = Array.new(inner_height) { '' }
46
- scaled.each.with_index do |y, x_index|
55
+ scaled[0..-2].each.with_index do |y, x_index|
56
+ last = x_index == scaled.length - 2
57
+
58
+ prev_y = x_index == 0 ? y : scaled[x_index - 1]
59
+ next_y = scaled[x_index + 1]
60
+
61
+ min_y = [(prev_y + y) / 2, y, last ? next_y : (y + next_y) / 2].min
62
+ min_y = (Y_AXIS_SCALE * min_y).round.to_f / Y_AXIS_SCALE
63
+
64
+ max_y = [(prev_y + y) / 2, y, last ? next_y : (y + next_y) / 2].max
65
+ max_y = (Y_AXIS_SCALE * max_y).round.to_f / Y_AXIS_SCALE
66
+
47
67
  @plot_lines.each.with_index do |row, row_index|
48
- bottom_half_index = 2 * (inner_height - row_index - 1)
49
- top_half_index = bottom_half_index + 1
50
-
51
- asc, next_y = if scaled.length == 1
52
- [true, y]
53
- elsif x_index == scaled.length - 1
54
- y >= scaled[x_index - 1]
55
- [true, y]
56
- else
57
- scaled[x_index + 1] >= y
58
- [true, scaled[x_index + 1]]
59
- end
60
- if asc
61
- top_half = y == top_half_index || (y...next_y).include?(top_half_index)
62
- bottom_half = y == bottom_half_index || (y...next_y).include?(bottom_half_index)
63
- else
64
- top_half = y == top_half_index || (next_y...y).include?(top_half_index)
65
- bottom_half = y == bottom_half_index || (next_y...y).include?(bottom_half_index)
66
- end
68
+ bottom_value = inner_height - row_index - 1
69
+ top_value = bottom_value + 1.0 / Y_AXIS_SCALE
70
+
71
+ top_half = min_y == top_value || (min_y <= top_value && top_value < max_y)
72
+ bottom_half = min_y == bottom_value || (min_y <= bottom_value && bottom_value < max_y)
73
+
67
74
  row << if top_half && bottom_half
68
75
  '█'
69
76
  elsif top_half
@@ -83,7 +90,7 @@ module WhirledPeas
83
90
  end
84
91
 
85
92
  def inner_width
86
- settings.width.nil? ? content.length : settings.width - 1
93
+ (settings.width.nil? ? content.length : settings.width) - 1
87
94
  end
88
95
 
89
96
  def axes_lines