whirled_peas 0.7.0 → 0.10.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 (220) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +25 -0
  4. data/README.md +467 -120
  5. data/Rakefile +1 -20
  6. data/bin/easing +33 -0
  7. data/bin/reset_cursor +11 -0
  8. data/bin/screen_test +68 -0
  9. data/examples/graph.rb +54 -0
  10. data/examples/intro.rb +3 -3
  11. data/examples/scrolling.rb +5 -4
  12. data/lib/data/themes.yaml +13 -0
  13. data/lib/whirled_peas.rb +12 -6
  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 +43 -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 +111 -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/themes.rb +76 -0
  33. data/lib/whirled_peas/command_line.rb +24 -212
  34. data/lib/whirled_peas/config.rb +56 -6
  35. data/lib/whirled_peas/device.rb +5 -0
  36. data/lib/whirled_peas/device/null_device.rb +8 -0
  37. data/lib/whirled_peas/device/output_file.rb +19 -0
  38. data/lib/whirled_peas/device/screen.rb +26 -0
  39. data/lib/whirled_peas/graphics/composer.rb +23 -2
  40. data/lib/whirled_peas/graphics/container_painter.rb +91 -0
  41. data/lib/whirled_peas/graphics/content_dimensions.rb +19 -0
  42. data/lib/whirled_peas/graphics/content_painter.rb +20 -0
  43. data/lib/whirled_peas/graphics/graph_dimensions.rb +12 -0
  44. data/lib/whirled_peas/graphics/graph_painter.rb +97 -0
  45. data/lib/whirled_peas/graphics/grid_painter.rb +1 -4
  46. data/lib/whirled_peas/graphics/painter.rb +10 -0
  47. data/lib/whirled_peas/graphics/renderer.rb +8 -2
  48. data/lib/whirled_peas/graphics/text_painter.rb +7 -11
  49. data/lib/whirled_peas/settings/border.rb +25 -4
  50. data/lib/whirled_peas/settings/container_settings.rb +2 -4
  51. data/lib/whirled_peas/settings/element_settings.rb +12 -3
  52. data/lib/whirled_peas/settings/graph_settings.rb +21 -0
  53. data/lib/whirled_peas/settings/grid_settings.rb +7 -0
  54. data/lib/whirled_peas/settings/text_settings.rb +1 -0
  55. data/lib/whirled_peas/settings/theme.rb +40 -0
  56. data/lib/whirled_peas/settings/theme_library.rb +63 -0
  57. data/lib/whirled_peas/utils/ansi.rb +13 -0
  58. data/lib/whirled_peas/utils/file_handler.rb +57 -0
  59. data/lib/whirled_peas/version.rb +1 -1
  60. data/screen_test/elements/box.frame +1 -1
  61. data/screen_test/elements/box.rb +1 -1
  62. data/screen_test/elements/graph.frame +1 -0
  63. data/screen_test/elements/graph.rb +12 -0
  64. data/screen_test/elements/grid.frame +1 -1
  65. data/screen_test/elements/grid.rb +1 -1
  66. data/screen_test/elements/screen_overflow_x.frame +1 -1
  67. data/screen_test/elements/screen_overflow_x.rb +1 -1
  68. data/screen_test/elements/screen_overflow_y.frame +1 -1
  69. data/screen_test/elements/screen_overflow_y.rb +1 -1
  70. data/screen_test/elements/text.frame +1 -1
  71. data/screen_test/elements/text.rb +1 -1
  72. data/screen_test/elements/text_multiline.frame +1 -1
  73. data/screen_test/elements/text_multiline.rb +1 -1
  74. data/screen_test/elements/theme.frame +1 -0
  75. data/screen_test/elements/theme.rb +26 -0
  76. data/screen_test/settings/align/box_around.frame +1 -1
  77. data/screen_test/settings/align/box_around.rb +1 -1
  78. data/screen_test/settings/align/box_between.frame +1 -1
  79. data/screen_test/settings/align/box_between.rb +1 -1
  80. data/screen_test/settings/align/box_center.frame +1 -1
  81. data/screen_test/settings/align/box_center.rb +1 -1
  82. data/screen_test/settings/align/box_default.frame +1 -1
  83. data/screen_test/settings/align/box_default.rb +1 -1
  84. data/screen_test/settings/align/box_evenly.frame +1 -1
  85. data/screen_test/settings/align/box_evenly.rb +1 -1
  86. data/screen_test/settings/align/box_left.frame +1 -1
  87. data/screen_test/settings/align/box_left.rb +1 -1
  88. data/screen_test/settings/align/box_right.frame +1 -1
  89. data/screen_test/settings/align/box_right.rb +1 -1
  90. data/screen_test/settings/align/children_center.frame +1 -1
  91. data/screen_test/settings/align/children_center.rb +1 -1
  92. data/screen_test/settings/align/children_left.frame +1 -1
  93. data/screen_test/settings/align/children_left.rb +1 -1
  94. data/screen_test/settings/align/children_right.frame +1 -1
  95. data/screen_test/settings/align/children_right.rb +1 -1
  96. data/screen_test/settings/align/grid_center.frame +1 -1
  97. data/screen_test/settings/align/grid_center.rb +1 -1
  98. data/screen_test/settings/align/grid_default.frame +1 -1
  99. data/screen_test/settings/align/grid_default.rb +1 -1
  100. data/screen_test/settings/align/grid_left.frame +1 -1
  101. data/screen_test/settings/align/grid_left.rb +1 -1
  102. data/screen_test/settings/align/grid_right.frame +1 -1
  103. data/screen_test/settings/align/grid_right.rb +1 -1
  104. data/screen_test/settings/ansi/bold.frame +1 -1
  105. data/screen_test/settings/ansi/bold.rb +1 -1
  106. data/screen_test/settings/ansi/color.frame +1 -1
  107. data/screen_test/settings/ansi/color.rb +1 -1
  108. data/screen_test/settings/ansi/underline.frame +1 -1
  109. data/screen_test/settings/ansi/underline.rb +1 -1
  110. data/screen_test/settings/border.frame +1 -1
  111. data/screen_test/settings/border.rb +1 -1
  112. data/screen_test/settings/flow/box_b2t.frame +1 -1
  113. data/screen_test/settings/flow/box_b2t.rb +1 -1
  114. data/screen_test/settings/flow/box_l2r.frame +1 -1
  115. data/screen_test/settings/flow/box_l2r.rb +1 -1
  116. data/screen_test/settings/flow/box_r2l.frame +1 -1
  117. data/screen_test/settings/flow/box_r2l.rb +1 -1
  118. data/screen_test/settings/flow/box_t2b.frame +1 -1
  119. data/screen_test/settings/flow/box_t2b.rb +1 -1
  120. data/screen_test/settings/flow/grid_b2t.frame +1 -1
  121. data/screen_test/settings/flow/grid_b2t.rb +2 -2
  122. data/screen_test/settings/flow/grid_l2r.frame +1 -1
  123. data/screen_test/settings/flow/grid_l2r.rb +2 -2
  124. data/screen_test/settings/flow/grid_r2l.frame +1 -1
  125. data/screen_test/settings/flow/grid_r2l.rb +2 -2
  126. data/screen_test/settings/flow/grid_t2b.frame +1 -1
  127. data/screen_test/settings/flow/grid_t2b.rb +2 -2
  128. data/screen_test/settings/height/box.frame +1 -1
  129. data/screen_test/settings/height/box.rb +1 -1
  130. data/screen_test/settings/height/box_border_sizing.frame +1 -1
  131. data/screen_test/settings/height/box_border_sizing.rb +1 -1
  132. data/screen_test/settings/height/grid.frame +1 -1
  133. data/screen_test/settings/height/grid.rb +1 -1
  134. data/screen_test/settings/height/overflow_box.frame +1 -1
  135. data/screen_test/settings/height/overflow_box.rb +1 -1
  136. data/screen_test/settings/height/overflow_box_l2r.frame +1 -1
  137. data/screen_test/settings/height/overflow_box_l2r.rb +1 -1
  138. data/screen_test/settings/height/overflow_box_t2b.frame +1 -1
  139. data/screen_test/settings/height/overflow_box_t2b.rb +1 -1
  140. data/screen_test/settings/height/overflow_grid.frame +1 -1
  141. data/screen_test/settings/height/overflow_grid.rb +1 -1
  142. data/screen_test/settings/margin.frame +1 -1
  143. data/screen_test/settings/margin.rb +1 -1
  144. data/screen_test/settings/padding.frame +1 -1
  145. data/screen_test/settings/padding.rb +1 -1
  146. data/screen_test/settings/position/box_left.frame +1 -1
  147. data/screen_test/settings/position/box_left.rb +1 -1
  148. data/screen_test/settings/position/box_left_negative.frame +1 -1
  149. data/screen_test/settings/position/box_left_negative.rb +1 -1
  150. data/screen_test/settings/position/box_top.frame +1 -1
  151. data/screen_test/settings/position/box_top.rb +1 -1
  152. data/screen_test/settings/position/box_top_negative.frame +1 -1
  153. data/screen_test/settings/position/box_top_negative.rb +1 -1
  154. data/screen_test/settings/position/grid_left.frame +1 -1
  155. data/screen_test/settings/position/grid_left.rb +1 -1
  156. data/screen_test/settings/position/grid_left_negative.frame +1 -1
  157. data/screen_test/settings/position/grid_left_negative.rb +1 -1
  158. data/screen_test/settings/position/grid_top.frame +1 -1
  159. data/screen_test/settings/position/grid_top.rb +1 -1
  160. data/screen_test/settings/position/grid_top_negative.frame +1 -1
  161. data/screen_test/settings/position/grid_top_negative.rb +1 -1
  162. data/screen_test/settings/scroll/horiz_box.frame +1 -1
  163. data/screen_test/settings/scroll/horiz_box.rb +1 -1
  164. data/screen_test/settings/scroll/horiz_box_align_center.rb +1 -1
  165. data/screen_test/settings/scroll/horiz_box_align_right.rb +1 -1
  166. data/screen_test/settings/scroll/vert_box.frame +1 -1
  167. data/screen_test/settings/scroll/vert_box.rb +1 -1
  168. data/screen_test/settings/title_font.frame +1 -1
  169. data/screen_test/settings/title_font.rb +1 -1
  170. data/screen_test/settings/valign/box_around.frame +1 -1
  171. data/screen_test/settings/valign/box_around.rb +1 -1
  172. data/screen_test/settings/valign/box_between.frame +1 -1
  173. data/screen_test/settings/valign/box_between.rb +1 -1
  174. data/screen_test/settings/valign/box_bottom.frame +1 -1
  175. data/screen_test/settings/valign/box_bottom.rb +1 -1
  176. data/screen_test/settings/valign/box_default.frame +1 -1
  177. data/screen_test/settings/valign/box_default.rb +1 -1
  178. data/screen_test/settings/valign/box_evenly.frame +1 -1
  179. data/screen_test/settings/valign/box_evenly.rb +1 -1
  180. data/screen_test/settings/valign/box_middle.frame +1 -1
  181. data/screen_test/settings/valign/box_middle.rb +1 -1
  182. data/screen_test/settings/valign/box_top.frame +1 -1
  183. data/screen_test/settings/valign/box_top.rb +1 -1
  184. data/screen_test/settings/valign/grid_bottom.frame +1 -1
  185. data/screen_test/settings/valign/grid_bottom.rb +1 -1
  186. data/screen_test/settings/valign/grid_default.frame +1 -1
  187. data/screen_test/settings/valign/grid_default.rb +1 -1
  188. data/screen_test/settings/valign/grid_middle.frame +1 -1
  189. data/screen_test/settings/valign/grid_middle.rb +1 -1
  190. data/screen_test/settings/valign/grid_top.frame +1 -1
  191. data/screen_test/settings/valign/grid_top.rb +1 -1
  192. data/screen_test/settings/width/box_border_sizing.frame +1 -1
  193. data/screen_test/settings/width/box_border_sizing.rb +1 -1
  194. data/screen_test/settings/width/box_content.frame +1 -1
  195. data/screen_test/settings/width/box_content.rb +1 -1
  196. data/screen_test/settings/width/box_default.frame +1 -1
  197. data/screen_test/settings/width/box_default.rb +1 -1
  198. data/screen_test/settings/width/grid.frame +1 -1
  199. data/screen_test/settings/width/grid.rb +1 -1
  200. data/screen_test/settings/width/overflow_align_center.frame +1 -1
  201. data/screen_test/settings/width/overflow_align_center.rb +1 -1
  202. data/screen_test/settings/width/overflow_align_right.frame +1 -1
  203. data/screen_test/settings/width/overflow_align_right.rb +1 -1
  204. data/screen_test/settings/width/overflow_box.frame +1 -1
  205. data/screen_test/settings/width/overflow_box.rb +1 -1
  206. data/screen_test/settings/width/overflow_box_l2r.frame +1 -1
  207. data/screen_test/settings/width/overflow_box_l2r.rb +1 -1
  208. data/screen_test/settings/width/overflow_box_t2b.frame +1 -1
  209. data/screen_test/settings/width/overflow_box_t2b.rb +1 -1
  210. data/screen_test/settings/width/overflow_grid.frame +1 -1
  211. data/screen_test/settings/width/overflow_grid.rb +1 -1
  212. data/tools/whirled_peas/tools/screen_tester.rb +131 -65
  213. metadata +42 -9
  214. data/lib/whirled_peas/frame.rb +0 -6
  215. data/lib/whirled_peas/frame/consumer.rb +0 -30
  216. data/lib/whirled_peas/frame/debug_consumer.rb +0 -30
  217. data/lib/whirled_peas/frame/event_loop.rb +0 -90
  218. data/lib/whirled_peas/frame/producer.rb +0 -67
  219. data/lib/whirled_peas/graphics/screen.rb +0 -70
  220. data/lib/whirled_peas/graphics/text_dimensions.rb +0 -15
@@ -28,9 +28,6 @@ module WhirledPeas
28
28
 
29
29
  def dimensions
30
30
  @dimensions ||= begin
31
- if settings.num_cols.nil? || settings.num_cols == 0
32
- raise SettingsError, "`num_cols` must be set for GridSettings(#{name})"
33
- end
34
31
  num_cols = settings.num_cols
35
32
  num_rows = (num_children.to_f / num_cols).ceil
36
33
  content_width = 0
@@ -58,7 +55,7 @@ module WhirledPeas
58
55
  col_index, row_index = [index % dimensions.num_cols, index / dimensions.num_cols]
59
56
  col_index = dimensions.num_cols - col_index - 1 if settings.reverse_flow?
60
57
  else
61
- col_index, row_index = [index / dimensions.num_cols, index % dimensions.num_cols]
58
+ col_index, row_index = [index / dimensions.num_rows, index % dimensions.num_rows]
62
59
  row_index = dimensions.num_rows - row_index - 1 if settings.reverse_flow?
63
60
  end
64
61
  [col_index, row_index]
@@ -1,5 +1,7 @@
1
1
  module WhirledPeas
2
2
  module Graphics
3
+ # Abstract base Painter class. Given a canvas and start coordinates (left, top), a painter
4
+ # is responsible for generating the "strokes" that display the element.
3
5
  class Painter
4
6
  attr_reader :name, :settings
5
7
 
@@ -8,9 +10,17 @@ module WhirledPeas
8
10
  @name = name
9
11
  end
10
12
 
13
+ # Paint the element onto the canvas by yielding strokes to the block. A stroke is composed
14
+ # of a left, top, and chars. E.g.
15
+ #
16
+ # yield 10, 3, 'Hello World!'
17
+ #
18
+ # paints the string "Hello World!" in the 10th column from the left, 3rd row down.
11
19
  def paint(canvas, left, top, &block)
12
20
  end
13
21
 
22
+ # Return a dimension object that provider the `outer_width` and `outer_height` of the
23
+ # element being painted.
14
24
  def dimensions
15
25
  end
16
26
 
@@ -9,13 +9,19 @@ module WhirledPeas
9
9
  @height = height
10
10
  end
11
11
 
12
- def paint(&block)
12
+ def paint
13
13
  # Modify the template's settings so that it fills the entire screen
14
14
  template.settings.width = width
15
15
  template.settings.height = height
16
16
  template.settings.sizing = :border
17
17
  template.settings.set_margin(left: 0, top: 0, right: 0, bottom: 0)
18
- template.paint(Canvas.new(0, 0, width, height), 0, 0, &block)
18
+ strokes = [Utils::Ansi.cursor_visible(false), Utils::Ansi.cursor_pos, Utils::Ansi.clear_down]
19
+ template.paint(Canvas.new(0, 0, width, height), 0, 0) do |left, top, fstring|
20
+ next unless fstring.length > 0
21
+ strokes << Utils::Ansi.cursor_pos(left: left, top: top)
22
+ strokes << fstring
23
+ end
24
+ strokes.join
19
25
  end
20
26
 
21
27
  private
@@ -1,14 +1,12 @@
1
1
  require 'whirled_peas/utils/formatted_string'
2
2
  require 'whirled_peas/utils/title_font'
3
3
 
4
- require_relative 'painter'
5
- require_relative 'text_dimensions'
4
+ require_relative 'content_dimensions'
5
+ require_relative 'content_painter'
6
6
 
7
7
  module WhirledPeas
8
8
  module Graphics
9
- class TextPainter < Painter
10
- attr_reader :content
11
-
9
+ class TextPainter < ContentPainter
12
10
  def paint(canvas, left, top, &block)
13
11
  return unless canvas.writable?
14
12
  formatting = [*settings.color, *settings.bg_color]
@@ -16,17 +14,15 @@ module WhirledPeas
16
14
  if settings.underline? && settings.title_font.nil?
17
15
  formatting << Utils::Ansi::UNDERLINE
18
16
  end
19
- content.each.with_index do |line, index|
17
+ content_lines.each.with_index do |line, index|
20
18
  canvas.stroke(left, top + index, line, formatting, &block)
21
19
  end
22
20
  end
23
21
 
24
- def dimensions
25
- TextDimensions.new(content)
26
- end
22
+ private
27
23
 
28
- def content=(content)
29
- @content = if settings.title_font
24
+ def content_lines
25
+ @content_lines = if settings.title_font
30
26
  Utils::TitleFont.to_s(
31
27
  content, settings.title_font
32
28
  ).split("\n")
@@ -51,8 +51,20 @@ module WhirledPeas
51
51
  end
52
52
  end
53
53
 
54
+ def self.inherit(parent)
55
+ border = new(parent.theme)
56
+ border.inherit(parent)
57
+ border
58
+ end
59
+
60
+ attr_reader :theme
61
+
54
62
  attr_writer :left, :top, :right, :bottom, :inner_horiz, :inner_vert
55
63
 
64
+ def initialize(theme)
65
+ @theme = theme
66
+ end
67
+
56
68
  def left?
57
69
  @left == true
58
70
  end
@@ -82,20 +94,29 @@ module WhirledPeas
82
94
  end
83
95
 
84
96
  def style
85
- @style || Styles::DEFAULT
97
+ @_style || Styles::DEFAULT
86
98
  end
87
99
 
88
100
  def style=(val)
89
- @style = Styles.validate!(val)
101
+ @_style = Styles.validate!(val)
90
102
  end
91
103
 
92
104
  def color=(val)
93
- @color = TextColor.validate!(val)
105
+ @_color = TextColor.validate!(val)
94
106
  end
95
107
 
96
108
  def color
97
- @color || TextColor::DEFAULT
109
+ @_color || theme.border_color
98
110
  end
111
+
112
+ def inherit(parent)
113
+ @_style = parent._style
114
+ @_color = parent._color
115
+ end
116
+
117
+ protected
118
+
119
+ attr_reader :_style, :_color
99
120
  end
100
121
  end
101
122
  end
@@ -12,8 +12,6 @@ require_relative 'vert_alignment'
12
12
  module WhirledPeas
13
13
  module Settings
14
14
  class ContainerSettings < ElementSettings
15
- attr_accessor :width, :height
16
-
17
15
  def align
18
16
  @_align || Alignment::DEFAULT
19
17
  end
@@ -98,7 +96,7 @@ module WhirledPeas
98
96
  end
99
97
 
100
98
  def border
101
- @_border ||= Border.new
99
+ @_border ||= Border.new(theme)
102
100
  end
103
101
 
104
102
  def flow=(flow)
@@ -214,7 +212,7 @@ module WhirledPeas
214
212
  def inherit(parent)
215
213
  super
216
214
  return unless parent.is_a?(ContainerSettings)
217
- set_border(color: parent.border.color, style: parent.border.style)
215
+ @_border = Border.inherit(parent.border)
218
216
  end
219
217
 
220
218
  protected
@@ -8,13 +8,22 @@ module WhirledPeas
8
8
  module Settings
9
9
  class ElementSettings
10
10
  def self.inherit(parent)
11
- child = self.new
11
+ child = self.new(parent.theme)
12
12
  child.inherit(parent)
13
13
  child
14
14
  end
15
15
 
16
+ attr_accessor :theme, :width, :height
17
+
18
+ def initialize(theme)
19
+ @theme = theme
20
+ end
21
+
22
+ def validate!
23
+ end
24
+
16
25
  def bg_color
17
- @_bg_color || BgColor::DEFAULT
26
+ @_bg_color || theme.bg_color
18
27
  end
19
28
 
20
29
  def bg_color=(color)
@@ -30,7 +39,7 @@ module WhirledPeas
30
39
  end
31
40
 
32
41
  def color
33
- @_color || TextColor::DEFAULT
42
+ @_color || theme.color
34
43
  end
35
44
 
36
45
  def color=(color)
@@ -0,0 +1,21 @@
1
+ require_relative 'text_color'
2
+ require_relative 'element_settings'
3
+
4
+ module WhirledPeas
5
+ module Settings
6
+ class GraphSettings < ElementSettings
7
+ def axis_color
8
+ @_axis_color || theme.axis_color
9
+ end
10
+
11
+ def axis_color=(color)
12
+ @_axis_color = TextColor.validate!(color)
13
+ end
14
+
15
+ def validate!
16
+ super
17
+ raise SettingsError, "`height` must be set for GraphSettings" if height.nil?
18
+ end
19
+ end
20
+ end
21
+ end
@@ -7,6 +7,13 @@ module WhirledPeas
7
7
  class GridSettings < ContainerSettings
8
8
  attr_accessor :num_cols
9
9
 
10
+ def validate!
11
+ super
12
+ if num_cols.nil? || num_cols <= 0
13
+ raise SettingsError, "`num_cols` must be set to a positive number for GridSettings"
14
+ end
15
+ end
16
+
10
17
  def set_scrollbar(*)
11
18
  raise NotImplementedError, 'Grids do not support scrollbars'
12
19
  end
@@ -8,6 +8,7 @@ module WhirledPeas
8
8
  attr_reader :title_font
9
9
 
10
10
  def title_font=(font)
11
+ font = theme.title_font if font == :theme
11
12
  @title_font = Utils::TitleFont.validate!(font)
12
13
  end
13
14
  end
@@ -0,0 +1,40 @@
1
+ require 'whirled_peas/utils/title_font'
2
+
3
+ require_relative 'bg_color'
4
+ require_relative 'text_color'
5
+
6
+ module WhirledPeas
7
+ module Settings
8
+ class Theme
9
+ attr_reader :color, :bg_color, :title_font
10
+
11
+ def color=(value)
12
+ @color = TextColor.validate!(value)
13
+ end
14
+
15
+ def bg_color=(value)
16
+ @bg_color = BgColor.validate!(value)
17
+ end
18
+
19
+ def border_color=(value)
20
+ @border_color = TextColor.validate!(value)
21
+ end
22
+
23
+ def border_color
24
+ @border_color || color
25
+ end
26
+
27
+ def axis_color=(value)
28
+ @axis_color = TextColor.validate!(value)
29
+ end
30
+
31
+ def axis_color
32
+ @axis_color || border_color
33
+ end
34
+
35
+ def title_font=(value)
36
+ @title_font = Utils::TitleFont.validate!(value)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,63 @@
1
+ require 'yaml'
2
+
3
+ require_relative 'theme'
4
+
5
+ module WhirledPeas
6
+ module Settings
7
+ module ThemeLibrary
8
+ CONFIG_FILE = File.join(File.dirname(File.dirname(File.dirname(__FILE__))), 'data', 'themes.yaml')
9
+
10
+ class << self
11
+ def theme_names
12
+ themes.keys
13
+ end
14
+
15
+ def add(name, theme)
16
+ themes[name] = theme
17
+ end
18
+
19
+ def get(name)
20
+ unless themes.key?(name)
21
+ expected = themes.keys.map(&:inspect).join(', ')
22
+ raise ArgumentError, "Unknown theme: #{name.inspect}, expecting one of #{expected}"
23
+ end
24
+ themes[name]
25
+ end
26
+
27
+ def default_name
28
+ themes.keys.first
29
+ end
30
+
31
+ private
32
+
33
+ def themes
34
+ return @themes if @themes
35
+ @themes = {}
36
+ config = YAML.load_file(CONFIG_FILE)
37
+ config.each do |name, settings|
38
+ name = name.to_sym
39
+ theme = Theme.new
40
+ settings.each do |key, value|
41
+ case key
42
+ when 'color'
43
+ theme.color = value
44
+ when 'bg_color'
45
+ theme.bg_color = value
46
+ when 'border_color'
47
+ theme.border_color = value
48
+ when 'axis_color'
49
+ theme.axis_color = value
50
+ when 'title_font'
51
+ theme.title_font = value
52
+ else
53
+ raise ArgumentError, "Unexpected theme setting: #{key} in #{CONFIG_FILE}"
54
+ end
55
+ end
56
+ @themes[name] = theme
57
+ end
58
+ @themes
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -28,6 +28,19 @@ module WhirledPeas
28
28
  BRIGHT_OFFSET = 60
29
29
 
30
30
  class << self
31
+ def with_screen(output=STDOUT, width: nil, height: nil, &block)
32
+ require 'highline'
33
+ unless width && height
34
+ width, height = HighLine.new.terminal.terminal_size
35
+ end
36
+ yield width, height
37
+ ensure
38
+ output.print clear
39
+ output.print cursor_pos(top: height - 1)
40
+ output.print cursor_visible(true)
41
+ output.flush
42
+ end
43
+
31
44
  def cursor_pos(top: 0, left: 0)
32
45
  "#{ESC}[#{top + 1};#{left + 1}H"
33
46
  end
@@ -0,0 +1,57 @@
1
+ require 'base64'
2
+ require 'zlib'
3
+
4
+ module WhirledPeas
5
+ module Utils
6
+ module FileHandler
7
+ module FileWriter
8
+ VERSION = '1'
9
+
10
+ def self.write(fp, renders)
11
+ fp.puts renders.count
12
+ renders.each do |strokes|
13
+ encoded = Base64.encode64(strokes)
14
+ fp.puts encoded.count("\n")
15
+ fp.puts encoded
16
+ end
17
+ end
18
+ end
19
+ private_constant :FileWriter
20
+
21
+ class FileReaderV1
22
+ def self.read(fp)
23
+ num_renders = Integer(fp.readline.chomp, 10)
24
+ num_renders.times.map do
25
+ num_strokes = Integer(fp.readline.chomp, 10)
26
+ Base64.decode64(num_strokes.times.map { fp.readline }.join)
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :file
33
+ end
34
+ private_constant :FileReaderV1
35
+
36
+ READERS = {
37
+ '1' => FileReaderV1
38
+ }
39
+ private_constant :READERS
40
+
41
+ def self.write(file, renders)
42
+ Zlib::GzipWriter.open(file, Zlib::BEST_COMPRESSION) do |gz|
43
+ gz.puts FileWriter::VERSION
44
+ FileWriter.write(gz, renders)
45
+ end
46
+ end
47
+
48
+ def self.read(file)
49
+ Zlib::GzipReader.open(file) do |gz|
50
+ version = gz.gets.chomp
51
+ raise ArgumentError, "Invalid file: #{file}" unless READERS.key?(version)
52
+ READERS[version].read(gz)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end