whirled_peas 0.6.0 → 0.9.1
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +30 -1
- data/README.md +710 -136
- data/Rakefile +3 -32
- data/bin/easing +33 -0
- data/bin/reset_cursor +11 -0
- data/bin/screen_test +68 -0
- data/examples/graph.rb +54 -0
- data/examples/intro.rb +3 -3
- data/examples/scrolling.rb +5 -4
- data/lib/whirled_peas.rb +2 -4
- data/lib/whirled_peas/animator.rb +5 -0
- data/lib/whirled_peas/animator/debug_consumer.rb +17 -0
- data/lib/whirled_peas/animator/easing.rb +72 -0
- data/lib/whirled_peas/animator/frame.rb +5 -0
- data/lib/whirled_peas/animator/frameset.rb +33 -0
- data/lib/whirled_peas/animator/producer.rb +35 -0
- data/lib/whirled_peas/animator/renderer_consumer.rb +31 -0
- data/lib/whirled_peas/command.rb +5 -0
- data/lib/whirled_peas/command/base.rb +86 -0
- data/lib/whirled_peas/command/config_command.rb +44 -0
- data/lib/whirled_peas/command/debug.rb +21 -0
- data/lib/whirled_peas/command/fonts.rb +22 -0
- data/lib/whirled_peas/command/frame_command.rb +34 -0
- data/lib/whirled_peas/command/frames.rb +24 -0
- data/lib/whirled_peas/command/help.rb +38 -0
- data/lib/whirled_peas/command/play.rb +108 -0
- data/lib/whirled_peas/command/record.rb +57 -0
- data/lib/whirled_peas/command/still.rb +29 -0
- data/lib/whirled_peas/command_line.rb +22 -212
- data/lib/whirled_peas/config.rb +56 -6
- data/lib/whirled_peas/device.rb +5 -0
- data/lib/whirled_peas/device/null_device.rb +8 -0
- data/lib/whirled_peas/device/output_file.rb +19 -0
- data/lib/whirled_peas/device/screen.rb +26 -0
- data/lib/whirled_peas/graphics.rb +14 -0
- data/lib/whirled_peas/graphics/box_painter.rb +39 -46
- data/lib/whirled_peas/graphics/canvas.rb +22 -11
- data/lib/whirled_peas/graphics/composer.rb +18 -0
- data/lib/whirled_peas/graphics/container_coords.rb +6 -5
- data/lib/whirled_peas/graphics/container_dimensions.rb +26 -8
- data/lib/whirled_peas/graphics/container_painter.rb +133 -4
- data/lib/whirled_peas/graphics/content_dimensions.rb +19 -0
- data/lib/whirled_peas/graphics/content_painter.rb +20 -0
- data/lib/whirled_peas/graphics/graph_dimensions.rb +12 -0
- data/lib/whirled_peas/graphics/graph_painter.rb +97 -0
- data/lib/whirled_peas/graphics/grid_painter.rb +12 -14
- data/lib/whirled_peas/graphics/painter.rb +15 -1
- data/lib/whirled_peas/graphics/renderer.rb +13 -2
- data/lib/whirled_peas/graphics/text_painter.rb +9 -13
- data/lib/whirled_peas/settings/alignment.rb +24 -0
- data/lib/whirled_peas/settings/bg_color.rb +2 -0
- data/lib/whirled_peas/settings/border.rb +16 -16
- data/lib/whirled_peas/settings/color.rb +13 -14
- data/lib/whirled_peas/settings/container_settings.rb +126 -44
- data/lib/whirled_peas/settings/display_flow.rb +13 -11
- data/lib/whirled_peas/settings/element_settings.rb +8 -3
- data/lib/whirled_peas/settings/graph_settings.rb +21 -0
- data/lib/whirled_peas/settings/grid_settings.rb +12 -1
- data/lib/whirled_peas/settings/sizing.rb +19 -0
- data/lib/whirled_peas/settings/spacing.rb +34 -0
- data/lib/whirled_peas/settings/text_color.rb +2 -0
- data/lib/whirled_peas/settings/vert_alignment.rb +24 -0
- data/lib/whirled_peas/utils/ansi.rb +13 -0
- data/lib/whirled_peas/utils/file_handler.rb +57 -0
- data/lib/whirled_peas/utils/title_font.rb +1 -1
- data/lib/whirled_peas/version.rb +1 -1
- data/screen_test/{rendered/elements → elements}/box.frame +1 -1
- data/screen_test/{rendered/elements → elements}/box.rb +0 -0
- data/screen_test/elements/graph.frame +1 -0
- data/screen_test/elements/graph.rb +12 -0
- data/screen_test/elements/grid.frame +1 -0
- data/screen_test/{rendered/elements → elements}/grid.rb +0 -0
- data/screen_test/elements/screen_overflow_x.frame +1 -0
- data/screen_test/{rendered/elements/screen_overflow.rb → elements/screen_overflow_x.rb} +0 -0
- data/screen_test/elements/screen_overflow_y.frame +1 -0
- data/screen_test/elements/screen_overflow_y.rb +9 -0
- data/screen_test/elements/text.frame +1 -0
- data/screen_test/{rendered/elements → elements}/text.rb +0 -0
- data/screen_test/elements/text_multiline.frame +1 -0
- data/screen_test/{rendered/elements → elements}/text_multiline.rb +0 -0
- data/screen_test/settings/align/box_around.frame +1 -0
- data/screen_test/settings/align/box_around.rb +16 -0
- data/screen_test/settings/align/box_between.frame +1 -0
- data/screen_test/settings/align/box_between.rb +16 -0
- data/screen_test/settings/align/box_center.frame +1 -0
- data/screen_test/{rendered/settings/align/grid.rb → settings/align/box_center.rb} +7 -6
- data/screen_test/settings/align/box_default.frame +1 -0
- data/screen_test/settings/align/box_default.rb +20 -0
- data/screen_test/settings/align/box_evenly.frame +1 -0
- data/screen_test/settings/align/box_evenly.rb +16 -0
- data/screen_test/settings/align/box_left.frame +1 -0
- data/screen_test/settings/align/box_left.rb +21 -0
- data/screen_test/settings/align/box_right.frame +1 -0
- data/screen_test/settings/align/box_right.rb +21 -0
- data/screen_test/settings/align/children_center.frame +1 -0
- data/screen_test/settings/align/children_center.rb +15 -0
- data/screen_test/settings/align/children_left.frame +1 -0
- data/screen_test/settings/align/children_left.rb +15 -0
- data/screen_test/settings/align/children_right.frame +1 -0
- data/screen_test/settings/align/children_right.rb +15 -0
- data/screen_test/settings/align/grid_center.frame +1 -0
- data/screen_test/settings/align/grid_center.rb +18 -0
- data/screen_test/settings/align/grid_default.frame +1 -0
- data/screen_test/settings/align/grid_default.rb +17 -0
- data/screen_test/settings/align/grid_left.frame +1 -0
- data/screen_test/settings/align/grid_left.rb +18 -0
- data/screen_test/settings/align/grid_right.frame +1 -0
- data/screen_test/settings/align/grid_right.rb +18 -0
- data/screen_test/settings/ansi/bold.frame +1 -0
- data/screen_test/{rendered/settings/height/overflow_box_t2b.rb → settings/ansi/bold.rb} +4 -4
- data/screen_test/{rendered/settings → settings}/ansi/color.frame +1 -1
- data/screen_test/{rendered/settings → settings}/ansi/color.rb +0 -0
- data/screen_test/settings/ansi/underline.frame +1 -0
- data/screen_test/{rendered/settings → settings}/ansi/underline.rb +4 -5
- data/screen_test/{rendered/settings → settings}/border.frame +1 -1
- data/screen_test/{rendered/settings → settings}/border.rb +1 -1
- data/screen_test/settings/flow/box_b2t.frame +1 -0
- data/screen_test/settings/flow/box_b2t.rb +26 -0
- data/screen_test/settings/flow/box_l2r.frame +1 -0
- data/screen_test/settings/flow/box_l2r.rb +26 -0
- data/screen_test/settings/flow/box_r2l.frame +1 -0
- data/screen_test/settings/flow/box_r2l.rb +26 -0
- data/screen_test/settings/flow/box_t2b.frame +1 -0
- data/screen_test/settings/flow/box_t2b.rb +26 -0
- data/screen_test/settings/flow/grid_b2t.frame +1 -0
- data/screen_test/{rendered/settings → settings}/flow/grid_b2t.rb +1 -1
- data/screen_test/settings/flow/grid_l2r.frame +1 -0
- data/screen_test/{rendered/settings → settings}/flow/grid_l2r.rb +1 -1
- data/screen_test/settings/flow/grid_r2l.frame +1 -0
- data/screen_test/{rendered/settings → settings}/flow/grid_r2l.rb +1 -1
- data/screen_test/settings/flow/grid_t2b.frame +1 -0
- data/screen_test/{rendered/settings → settings}/flow/grid_t2b.rb +1 -1
- data/screen_test/settings/height/box.frame +1 -0
- data/screen_test/{rendered/settings → settings}/height/box.rb +0 -0
- data/screen_test/settings/height/box_border_sizing.frame +1 -0
- data/screen_test/settings/height/box_border_sizing.rb +15 -0
- data/screen_test/settings/height/grid.frame +1 -0
- data/screen_test/{rendered/settings → settings}/height/grid.rb +0 -0
- data/screen_test/settings/height/overflow_box.frame +1 -0
- data/screen_test/settings/height/overflow_box.rb +13 -0
- data/screen_test/settings/height/overflow_box_l2r.frame +1 -0
- data/screen_test/settings/height/overflow_box_l2r.rb +17 -0
- data/screen_test/settings/height/overflow_box_t2b.frame +1 -0
- data/screen_test/settings/height/overflow_box_t2b.rb +16 -0
- data/screen_test/settings/height/overflow_grid.frame +1 -0
- data/screen_test/{rendered/settings → settings}/height/overflow_grid.rb +0 -0
- data/screen_test/settings/margin.frame +1 -0
- data/screen_test/settings/margin.rb +16 -0
- data/screen_test/settings/padding.frame +1 -0
- data/screen_test/settings/padding.rb +13 -0
- data/screen_test/settings/position/box_left.frame +1 -0
- data/screen_test/{rendered/settings → settings}/position/box_left.rb +2 -2
- data/screen_test/settings/position/box_left_negative.frame +1 -0
- data/screen_test/{rendered/settings → settings}/position/box_left_negative.rb +2 -2
- data/screen_test/settings/position/box_top.frame +1 -0
- data/screen_test/{rendered/settings → settings}/position/box_top.rb +1 -1
- data/screen_test/settings/position/box_top_negative.frame +1 -0
- data/screen_test/{rendered/settings → settings}/position/box_top_negative.rb +2 -2
- data/screen_test/settings/position/grid_left.frame +1 -0
- data/screen_test/{rendered/settings → settings}/position/grid_left.rb +1 -1
- data/screen_test/settings/position/grid_left_negative.frame +1 -0
- data/screen_test/{rendered/settings → settings}/position/grid_left_negative.rb +1 -1
- data/screen_test/settings/position/grid_top.frame +1 -0
- data/screen_test/{rendered/settings → settings}/position/grid_top.rb +1 -1
- data/screen_test/settings/position/grid_top_negative.frame +1 -0
- data/screen_test/{rendered/settings → settings}/position/grid_top_negative.rb +1 -1
- data/screen_test/settings/scroll/horiz_box.frame +1 -0
- data/screen_test/settings/scroll/horiz_box.rb +17 -0
- data/screen_test/settings/scroll/horiz_box_align_center.rb +18 -0
- data/screen_test/settings/scroll/horiz_box_align_right.rb +18 -0
- data/screen_test/settings/scroll/vert_box.frame +1 -0
- data/screen_test/settings/scroll/vert_box.rb +20 -0
- data/screen_test/settings/title_font.frame +1 -0
- data/screen_test/{rendered/settings → settings}/title_font.rb +1 -1
- data/screen_test/settings/valign/box_around.frame +1 -0
- data/screen_test/settings/valign/box_around.rb +17 -0
- data/screen_test/settings/valign/box_between.frame +1 -0
- data/screen_test/settings/valign/box_between.rb +17 -0
- data/screen_test/settings/valign/box_bottom.frame +1 -0
- data/screen_test/settings/valign/box_bottom.rb +17 -0
- data/screen_test/settings/valign/box_default.frame +1 -0
- data/screen_test/settings/valign/box_default.rb +16 -0
- data/screen_test/settings/valign/box_evenly.frame +1 -0
- data/screen_test/settings/valign/box_evenly.rb +17 -0
- data/screen_test/settings/valign/box_middle.frame +1 -0
- data/screen_test/settings/valign/box_middle.rb +17 -0
- data/screen_test/settings/valign/box_top.frame +1 -0
- data/screen_test/settings/valign/box_top.rb +17 -0
- data/screen_test/settings/valign/grid_bottom.frame +1 -0
- data/screen_test/settings/valign/grid_bottom.rb +15 -0
- data/screen_test/settings/valign/grid_default.frame +1 -0
- data/screen_test/settings/valign/grid_default.rb +14 -0
- data/screen_test/settings/valign/grid_middle.frame +1 -0
- data/screen_test/settings/valign/grid_middle.rb +15 -0
- data/screen_test/settings/valign/grid_top.frame +1 -0
- data/screen_test/settings/valign/grid_top.rb +15 -0
- data/screen_test/settings/width/box_border_sizing.frame +1 -0
- data/screen_test/settings/width/box_border_sizing.rb +15 -0
- data/screen_test/settings/width/box_content.frame +1 -0
- data/screen_test/settings/width/box_content.rb +15 -0
- data/screen_test/settings/width/box_default.frame +1 -0
- data/screen_test/{rendered/settings/width/box.rb → settings/width/box_default.rb} +3 -2
- data/screen_test/settings/width/grid.frame +1 -0
- data/screen_test/{rendered/settings → settings}/width/grid.rb +2 -2
- data/screen_test/settings/width/overflow_align_center.frame +1 -0
- data/screen_test/settings/width/overflow_align_center.rb +14 -0
- data/screen_test/settings/width/overflow_align_right.frame +1 -0
- data/screen_test/settings/width/overflow_align_right.rb +14 -0
- data/screen_test/settings/width/overflow_box.frame +1 -0
- data/screen_test/settings/width/overflow_box.rb +13 -0
- data/screen_test/settings/width/overflow_box_l2r.frame +1 -0
- data/screen_test/settings/width/overflow_box_l2r.rb +16 -0
- data/screen_test/settings/width/overflow_box_t2b.frame +1 -0
- data/screen_test/settings/width/overflow_box_t2b.rb +17 -0
- data/screen_test/settings/width/overflow_grid.frame +1 -0
- data/screen_test/{rendered/settings → settings}/width/overflow_grid.rb +0 -0
- data/tools/whirled_peas/tools/screen_tester.rb +285 -0
- metadata +188 -105
- data/lib/whirled_peas/frame.rb +0 -6
- data/lib/whirled_peas/frame/consumer.rb +0 -30
- data/lib/whirled_peas/frame/debug_consumer.rb +0 -30
- data/lib/whirled_peas/frame/event_loop.rb +0 -90
- data/lib/whirled_peas/frame/producer.rb +0 -67
- data/lib/whirled_peas/graphics/screen.rb +0 -70
- data/lib/whirled_peas/graphics/text_dimensions.rb +0 -15
- data/lib/whirled_peas/settings/text_align.rb +0 -19
- data/screen_test/rendered/elements/grid.frame +0 -1
- data/screen_test/rendered/elements/screen_overflow.frame +0 -1
- data/screen_test/rendered/elements/text.frame +0 -1
- data/screen_test/rendered/elements/text_multiline.frame +0 -1
- data/screen_test/rendered/settings/align/box.frame +0 -1
- data/screen_test/rendered/settings/align/box.rb +0 -24
- data/screen_test/rendered/settings/align/children_center.frame +0 -1
- data/screen_test/rendered/settings/align/children_center.rb +0 -13
- data/screen_test/rendered/settings/align/children_left.frame +0 -1
- data/screen_test/rendered/settings/align/children_left.rb +0 -13
- data/screen_test/rendered/settings/align/children_right.frame +0 -1
- data/screen_test/rendered/settings/align/children_right.rb +0 -13
- data/screen_test/rendered/settings/align/grid.frame +0 -1
- data/screen_test/rendered/settings/ansi/bold.frame +0 -1
- data/screen_test/rendered/settings/ansi/bold.rb +0 -15
- data/screen_test/rendered/settings/ansi/underline.frame +0 -1
- data/screen_test/rendered/settings/flow/box_b2t.frame +0 -1
- data/screen_test/rendered/settings/flow/box_b2t.rb +0 -24
- data/screen_test/rendered/settings/flow/box_l2r.frame +0 -1
- data/screen_test/rendered/settings/flow/box_l2r.rb +0 -24
- data/screen_test/rendered/settings/flow/box_r2l.frame +0 -1
- data/screen_test/rendered/settings/flow/box_r2l.rb +0 -24
- data/screen_test/rendered/settings/flow/box_t2b.frame +0 -1
- data/screen_test/rendered/settings/flow/box_t2b.rb +0 -24
- data/screen_test/rendered/settings/flow/grid_b2t.frame +0 -1
- data/screen_test/rendered/settings/flow/grid_l2r.frame +0 -1
- data/screen_test/rendered/settings/flow/grid_r2l.frame +0 -1
- data/screen_test/rendered/settings/flow/grid_t2b.frame +0 -1
- data/screen_test/rendered/settings/height/box.frame +0 -1
- data/screen_test/rendered/settings/height/grid.frame +0 -1
- data/screen_test/rendered/settings/height/overflow_box.frame +0 -1
- data/screen_test/rendered/settings/height/overflow_box.rb +0 -13
- data/screen_test/rendered/settings/height/overflow_box_l2r.frame +0 -1
- data/screen_test/rendered/settings/height/overflow_box_l2r.rb +0 -15
- data/screen_test/rendered/settings/height/overflow_box_t2b.frame +0 -1
- data/screen_test/rendered/settings/height/overflow_grid.frame +0 -1
- data/screen_test/rendered/settings/margin.frame +0 -1
- data/screen_test/rendered/settings/margin.rb +0 -14
- data/screen_test/rendered/settings/padding.frame +0 -1
- data/screen_test/rendered/settings/padding.rb +0 -11
- data/screen_test/rendered/settings/position/box_left.frame +0 -1
- data/screen_test/rendered/settings/position/box_left_negative.frame +0 -1
- data/screen_test/rendered/settings/position/box_top.frame +0 -1
- data/screen_test/rendered/settings/position/box_top_negative.frame +0 -1
- data/screen_test/rendered/settings/position/grid_left.frame +0 -1
- data/screen_test/rendered/settings/position/grid_left_negative.frame +0 -1
- data/screen_test/rendered/settings/position/grid_top.frame +0 -1
- data/screen_test/rendered/settings/position/grid_top_negative.frame +0 -1
- data/screen_test/rendered/settings/scroll/horiz_box.frame +0 -1
- data/screen_test/rendered/settings/scroll/horiz_box.rb +0 -15
- data/screen_test/rendered/settings/scroll/vert_box.frame +0 -1
- data/screen_test/rendered/settings/scroll/vert_box.rb +0 -18
- data/screen_test/rendered/settings/title_font.frame +0 -1
- data/screen_test/rendered/settings/width/box.frame +0 -1
- data/screen_test/rendered/settings/width/grid.frame +0 -1
- data/screen_test/rendered/settings/width/overflow_box.frame +0 -1
- data/screen_test/rendered/settings/width/overflow_box.rb +0 -11
- data/screen_test/rendered/settings/width/overflow_box_l2r.frame +0 -1
- data/screen_test/rendered/settings/width/overflow_box_l2r.rb +0 -14
- data/screen_test/rendered/settings/width/overflow_box_t2b.frame +0 -1
- data/screen_test/rendered/settings/width/overflow_box_t2b.rb +0 -15
- data/screen_test/rendered/settings/width/overflow_grid.frame +0 -1
- data/screen_test/screen_tester.rb +0 -201
@@ -0,0 +1,19 @@
|
|
1
|
+
module WhirledPeas
|
2
|
+
module Graphics
|
3
|
+
class ContentDimensions
|
4
|
+
attr_reader :outer_width, :outer_height
|
5
|
+
|
6
|
+
def initialize(settings, content)
|
7
|
+
if settings.width
|
8
|
+
@outer_width = settings.width
|
9
|
+
else
|
10
|
+
@outer_width = 0
|
11
|
+
content.each do |line|
|
12
|
+
@outer_width = line.length if line.length > @outer_width
|
13
|
+
end
|
14
|
+
end
|
15
|
+
@outer_height = settings.height || content.length
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative 'painter'
|
2
|
+
|
3
|
+
module WhirledPeas
|
4
|
+
module Graphics
|
5
|
+
class ContentPainter < Painter
|
6
|
+
attr_accessor :content
|
7
|
+
|
8
|
+
def dimensions
|
9
|
+
ContentDimensions.new(settings, content_lines)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def content_lines
|
15
|
+
raise NotImplementedError, "#{self.class} must implement #content_lines"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
private_constant :ContentPainter
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'whirled_peas/utils/ansi'
|
2
|
+
|
3
|
+
require_relative 'content_painter'
|
4
|
+
|
5
|
+
module WhirledPeas
|
6
|
+
module Graphics
|
7
|
+
class GraphPainter < ContentPainter
|
8
|
+
def paint(canvas, left, top, &block)
|
9
|
+
axis_formatting = [*settings.axis_color, *settings.bg_color]
|
10
|
+
plot_formatting = [*settings.color, *settings.bg_color]
|
11
|
+
axes_lines.each.with_index do |axis_line, row_index|
|
12
|
+
canvas.stroke(left, top + row_index, axis_line, axis_formatting, &block)
|
13
|
+
next if row_index >= plot_lines.length
|
14
|
+
canvas.stroke(left + 1, top + row_index, plot_lines[row_index], plot_formatting, &block)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def content_lines
|
21
|
+
axes_lines
|
22
|
+
end
|
23
|
+
|
24
|
+
def plot_lines
|
25
|
+
return @plot_lines if @plot_lines
|
26
|
+
min_y = 1.0 / 0
|
27
|
+
max_y = -1.0 / 0
|
28
|
+
if settings.width
|
29
|
+
interpolated = inner_width.times.map do |i|
|
30
|
+
x = (i * (content.length - 1).to_f / inner_width).floor
|
31
|
+
max_y = content[x] if content[x] > max_y
|
32
|
+
min_y = content[x] if content[x] < min_y
|
33
|
+
content[x]
|
34
|
+
end
|
35
|
+
else
|
36
|
+
interpolated = content
|
37
|
+
content.each do |y|
|
38
|
+
max_y = y if y > max_y
|
39
|
+
min_y = y if y < min_y
|
40
|
+
end
|
41
|
+
end
|
42
|
+
scaled = interpolated.map do |y|
|
43
|
+
(2 * inner_height * (y - min_y).to_f / (max_y - min_y)).floor
|
44
|
+
end
|
45
|
+
@plot_lines = Array.new(inner_height) { '' }
|
46
|
+
scaled.each.with_index do |y, x_index|
|
47
|
+
@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
|
67
|
+
row << if top_half && bottom_half
|
68
|
+
'█'
|
69
|
+
elsif top_half
|
70
|
+
'▀'
|
71
|
+
elsif bottom_half
|
72
|
+
'▄'
|
73
|
+
else
|
74
|
+
' '
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
@plot_lines
|
79
|
+
end
|
80
|
+
|
81
|
+
def inner_height
|
82
|
+
settings.height - 1
|
83
|
+
end
|
84
|
+
|
85
|
+
def inner_width
|
86
|
+
settings.width.nil? ? content.length : settings.width - 1
|
87
|
+
end
|
88
|
+
|
89
|
+
def axes_lines
|
90
|
+
return @axes_lines if @axes_lines
|
91
|
+
@axes_lines = inner_height.times.map { '┃' }
|
92
|
+
@axes_lines << '┗' + '━' * inner_width
|
93
|
+
@axes_lines
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -4,32 +4,30 @@ require_relative 'container_painter'
|
|
4
4
|
module WhirledPeas
|
5
5
|
module Graphics
|
6
6
|
class GridPainter < ContainerPainter
|
7
|
-
def paint(canvas, &block)
|
7
|
+
def paint(canvas, left, top, &block)
|
8
8
|
super
|
9
9
|
return unless canvas.writable?
|
10
10
|
each_child.with_index do |child, index|
|
11
11
|
col_index, row_index = grid_cell(index)
|
12
|
-
|
13
|
-
|
14
|
-
content_left += (dimensions.content_width - child.dimensions.outer_width) / 2
|
15
|
-
elsif settings.align_right?
|
16
|
-
content_left += dimensions.content_width - child.dimensions.outer_width
|
17
|
-
end
|
12
|
+
left_offset, _ = horiz_justify_offset(child.dimensions.outer_width)
|
13
|
+
top_offset, _ = vert_justify_offset(child.dimensions.outer_height)
|
18
14
|
child_canvas = canvas.child(
|
19
|
-
content_left,
|
20
|
-
coords(
|
15
|
+
coords(left, top).content_left(col_index) + left_offset,
|
16
|
+
coords(left, top).content_top(row_index) + top_offset,
|
21
17
|
[dimensions.content_width, child.dimensions.outer_width].min,
|
22
18
|
[dimensions.content_height, child.dimensions.outer_height].min
|
23
19
|
)
|
24
|
-
child.paint(
|
20
|
+
child.paint(
|
21
|
+
child_canvas,
|
22
|
+
coords(left, top).content_left(col_index) + left_offset,
|
23
|
+
coords(left, top).content_top(row_index) + top_offset,
|
24
|
+
&block
|
25
|
+
)
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
28
29
|
def dimensions
|
29
30
|
@dimensions ||= begin
|
30
|
-
if settings.num_cols.nil? || settings.num_cols == 0
|
31
|
-
raise SettingsError, "`num_cols` must be set for GridSettings(#{name})"
|
32
|
-
end
|
33
31
|
num_cols = settings.num_cols
|
34
32
|
num_rows = (num_children.to_f / num_cols).ceil
|
35
33
|
content_width = 0
|
@@ -57,7 +55,7 @@ module WhirledPeas
|
|
57
55
|
col_index, row_index = [index % dimensions.num_cols, index / dimensions.num_cols]
|
58
56
|
col_index = dimensions.num_cols - col_index - 1 if settings.reverse_flow?
|
59
57
|
else
|
60
|
-
col_index, row_index = [index / dimensions.
|
58
|
+
col_index, row_index = [index / dimensions.num_rows, index % dimensions.num_rows]
|
61
59
|
row_index = dimensions.num_rows - row_index - 1 if settings.reverse_flow?
|
62
60
|
end
|
63
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,11 +10,23 @@ module WhirledPeas
|
|
8
10
|
@name = name
|
9
11
|
end
|
10
12
|
|
11
|
-
|
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.
|
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
|
26
|
+
|
27
|
+
def inspect
|
28
|
+
"#{self.class.name.split('::').last}(name=#{name.inspect})"
|
29
|
+
end
|
16
30
|
end
|
17
31
|
private_constant :Painter
|
18
32
|
end
|
@@ -9,8 +9,19 @@ module WhirledPeas
|
|
9
9
|
@height = height
|
10
10
|
end
|
11
11
|
|
12
|
-
def paint
|
13
|
-
template
|
12
|
+
def paint
|
13
|
+
# Modify the template's settings so that it fills the entire screen
|
14
|
+
template.settings.width = width
|
15
|
+
template.settings.height = height
|
16
|
+
template.settings.sizing = :border
|
17
|
+
template.settings.set_margin(left: 0, top: 0, right: 0, bottom: 0)
|
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
|
14
25
|
end
|
15
26
|
|
16
27
|
private
|
@@ -1,32 +1,28 @@
|
|
1
1
|
require 'whirled_peas/utils/formatted_string'
|
2
2
|
require 'whirled_peas/utils/title_font'
|
3
3
|
|
4
|
-
require_relative '
|
5
|
-
require_relative '
|
4
|
+
require_relative 'content_dimensions'
|
5
|
+
require_relative 'content_painter'
|
6
6
|
|
7
7
|
module WhirledPeas
|
8
8
|
module Graphics
|
9
|
-
class TextPainter <
|
10
|
-
|
11
|
-
|
12
|
-
def paint(canvas, &block)
|
9
|
+
class TextPainter < ContentPainter
|
10
|
+
def paint(canvas, left, top, &block)
|
13
11
|
return unless canvas.writable?
|
14
12
|
formatting = [*settings.color, *settings.bg_color]
|
15
13
|
formatting << Utils::Ansi::BOLD if settings.bold?
|
16
14
|
if settings.underline? && settings.title_font.nil?
|
17
15
|
formatting << Utils::Ansi::UNDERLINE
|
18
16
|
end
|
19
|
-
|
20
|
-
canvas.stroke(
|
17
|
+
content_lines.each.with_index do |line, index|
|
18
|
+
canvas.stroke(left, top + index, line, formatting, &block)
|
21
19
|
end
|
22
20
|
end
|
23
21
|
|
24
|
-
|
25
|
-
TextDimensions.new(content)
|
26
|
-
end
|
22
|
+
private
|
27
23
|
|
28
|
-
def
|
29
|
-
@
|
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")
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module WhirledPeas
|
2
|
+
module Settings
|
3
|
+
module Alignment
|
4
|
+
LEFT = :left
|
5
|
+
CENTER = :center
|
6
|
+
RIGHT = :right
|
7
|
+
BETWEEN = :between
|
8
|
+
AROUND = :around
|
9
|
+
EVENLY = :evenly
|
10
|
+
|
11
|
+
DEFAULT = LEFT
|
12
|
+
|
13
|
+
VALID = [LEFT, CENTER, RIGHT, BETWEEN, AROUND, EVENLY]
|
14
|
+
private_constant :VALID
|
15
|
+
|
16
|
+
def self.validate!(align)
|
17
|
+
return if align.nil?
|
18
|
+
return align if VALID.include?(align)
|
19
|
+
raise ArgumentError, "Unsupported alignment: #{align.inspect}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
private_constant :Alignment
|
23
|
+
end
|
24
|
+
end
|
@@ -34,20 +34,20 @@ module WhirledPeas
|
|
34
34
|
'╚', '═', '╩', '╝'
|
35
35
|
)
|
36
36
|
|
37
|
+
DEFAULT = BOLD
|
38
|
+
|
37
39
|
def self.validate!(style)
|
38
|
-
return
|
40
|
+
return if style.nil?
|
41
|
+
return style if style.is_a?(Border::Style)
|
39
42
|
if style.is_a?(Symbol)
|
40
|
-
|
41
|
-
|
42
|
-
style = self.const_get(style.upcase)
|
43
|
-
raise ArgumentError, error_message unless style.is_a?(Style)
|
44
|
-
style
|
45
|
-
rescue NameError
|
46
|
-
raise ArgumentError, error_message
|
47
|
-
end
|
48
|
-
else
|
49
|
-
style
|
43
|
+
style_class = self.const_get(style.upcase)
|
44
|
+
return style_class if style_class.is_a?(Border::Style)
|
50
45
|
end
|
46
|
+
error_message = "Unsupported border style: #{style.inspect}"
|
47
|
+
raise ArgumentError, error_message
|
48
|
+
rescue NameError
|
49
|
+
error_message = "Unsupported border style: #{style.inspect}"
|
50
|
+
raise ArgumentError, error_message
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
@@ -82,20 +82,20 @@ module WhirledPeas
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def style
|
85
|
-
@style || Styles::
|
85
|
+
@style || Styles::DEFAULT
|
86
86
|
end
|
87
87
|
|
88
88
|
def style=(val)
|
89
89
|
@style = Styles.validate!(val)
|
90
90
|
end
|
91
91
|
|
92
|
-
def color
|
93
|
-
@color || TextColor::WHITE
|
94
|
-
end
|
95
|
-
|
96
92
|
def color=(val)
|
97
93
|
@color = TextColor.validate!(val)
|
98
94
|
end
|
95
|
+
|
96
|
+
def color
|
97
|
+
@color || TextColor::DEFAULT
|
98
|
+
end
|
99
99
|
end
|
100
100
|
end
|
101
101
|
end
|
@@ -13,25 +13,24 @@ module WhirledPeas
|
|
13
13
|
# @return [Color|Symbol] the value passed in if valid, otherwise an ArgumentError
|
14
14
|
# is raised.
|
15
15
|
def self.validate!(color)
|
16
|
-
return
|
16
|
+
return if color.nil?
|
17
|
+
return color if color.is_a?(self)
|
17
18
|
if color.is_a?(Symbol)
|
18
|
-
error_message = "Unsupported #{self.name.split('::').last}: #{color.inspect}"
|
19
19
|
match = color.to_s.match(/^(bright_)?(\w+)$/)
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
else
|
27
|
-
color
|
20
|
+
color_class = self.const_get(match[2].upcase)
|
21
|
+
if color_class.is_a?(self)
|
22
|
+
if !match[1]
|
23
|
+
return color_class
|
24
|
+
elsif !color_class.bright?
|
25
|
+
return color_class.bright
|
28
26
|
end
|
29
|
-
rescue NameError
|
30
|
-
raise ArgumentError, error_message
|
31
27
|
end
|
32
|
-
else
|
33
|
-
color
|
34
28
|
end
|
29
|
+
error_message = "Unsupported #{self.name.split('::').last}: #{color.inspect}"
|
30
|
+
raise ArgumentError, error_message
|
31
|
+
rescue NameError
|
32
|
+
error_message = "Unsupported #{self.name.split('::').last}: #{color.inspect}"
|
33
|
+
raise ArgumentError, error_message
|
35
34
|
end
|
36
35
|
|
37
36
|
def initialize(code, bright=false)
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require_relative 'alignment'
|
1
2
|
require_relative 'border'
|
2
3
|
require_relative 'display_flow'
|
3
4
|
require_relative 'element_settings'
|
@@ -5,44 +6,87 @@ require_relative 'margin'
|
|
5
6
|
require_relative 'padding'
|
6
7
|
require_relative 'position'
|
7
8
|
require_relative 'scrollbar'
|
9
|
+
require_relative 'sizing'
|
10
|
+
require_relative 'vert_alignment'
|
8
11
|
|
9
12
|
module WhirledPeas
|
10
13
|
module Settings
|
11
14
|
class ContainerSettings < ElementSettings
|
12
|
-
attr_accessor :width, :height
|
13
|
-
|
14
15
|
def align
|
15
|
-
@_align ||
|
16
|
+
@_align || Alignment::DEFAULT
|
16
17
|
end
|
17
18
|
|
18
19
|
def align_left?
|
19
|
-
align ==
|
20
|
+
align == Alignment::LEFT
|
20
21
|
end
|
21
22
|
|
22
23
|
def align_center?
|
23
|
-
align ==
|
24
|
+
align == Alignment::CENTER
|
24
25
|
end
|
25
26
|
|
26
27
|
def align_right?
|
27
|
-
align ==
|
28
|
+
align == Alignment::RIGHT
|
29
|
+
end
|
30
|
+
|
31
|
+
def align_between?
|
32
|
+
align == Alignment::BETWEEN
|
33
|
+
end
|
34
|
+
|
35
|
+
def align_around?
|
36
|
+
align == Alignment::AROUND
|
37
|
+
end
|
38
|
+
|
39
|
+
def align_evenly?
|
40
|
+
align == Alignment::EVENLY
|
28
41
|
end
|
29
42
|
|
30
43
|
def align=(align)
|
31
|
-
@_align =
|
44
|
+
@_align = Alignment.validate!(align)
|
45
|
+
end
|
46
|
+
|
47
|
+
def valign
|
48
|
+
@_valign || VertAlignment::DEFAULT
|
49
|
+
end
|
50
|
+
|
51
|
+
def valign_top?
|
52
|
+
valign == VertAlignment::TOP
|
53
|
+
end
|
54
|
+
|
55
|
+
def valign_middle?
|
56
|
+
valign == VertAlignment::MIDDLE
|
57
|
+
end
|
58
|
+
|
59
|
+
def valign_bottom?
|
60
|
+
valign == VertAlignment::BOTTOM
|
61
|
+
end
|
62
|
+
|
63
|
+
def valign_between?
|
64
|
+
valign == VertAlignment::BETWEEN
|
65
|
+
end
|
66
|
+
|
67
|
+
def valign_around?
|
68
|
+
valign == VertAlignment::AROUND
|
69
|
+
end
|
70
|
+
|
71
|
+
def valign_evenly?
|
72
|
+
valign == VertAlignment::EVENLY
|
73
|
+
end
|
74
|
+
|
75
|
+
def valign=(valign)
|
76
|
+
@_valign = VertAlignment.validate!(valign)
|
32
77
|
end
|
33
78
|
|
34
79
|
def set_border(
|
35
80
|
left: nil, top: nil, right: nil, bottom: nil, inner_horiz: nil, inner_vert: nil, style: nil, color: nil
|
36
81
|
)
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
@_border.color = color unless color.nil?
|
82
|
+
border.left = left unless left.nil?
|
83
|
+
border.top = top unless top.nil?
|
84
|
+
border.right = right unless right.nil?
|
85
|
+
border.bottom = bottom unless bottom.nil?
|
86
|
+
border.inner_horiz = inner_horiz unless inner_horiz.nil?
|
87
|
+
border.inner_vert = inner_vert unless inner_vert.nil?
|
88
|
+
border.style = style unless style.nil?
|
89
|
+
border.color = color unless color.nil?
|
46
90
|
end
|
47
91
|
|
48
92
|
def full_border(style: nil, color: nil)
|
@@ -52,7 +96,7 @@ module WhirledPeas
|
|
52
96
|
end
|
53
97
|
|
54
98
|
def border
|
55
|
-
@_border
|
99
|
+
@_border ||= Border.new
|
56
100
|
end
|
57
101
|
|
58
102
|
def flow=(flow)
|
@@ -60,7 +104,7 @@ module WhirledPeas
|
|
60
104
|
end
|
61
105
|
|
62
106
|
def flow
|
63
|
-
@_flow || DisplayFlow::
|
107
|
+
@_flow || DisplayFlow::DEFAULT
|
64
108
|
end
|
65
109
|
|
66
110
|
def horizontal_flow?
|
@@ -79,61 +123,99 @@ module WhirledPeas
|
|
79
123
|
!forward_flow?
|
80
124
|
end
|
81
125
|
|
82
|
-
def set_margin(left: nil, top: nil, right: nil, bottom: nil)
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
126
|
+
def set_margin(left: nil, top: nil, right: nil, bottom: nil, horiz: nil, vert: nil)
|
127
|
+
if horiz && (left || right)
|
128
|
+
raise ArgumentError, 'Cannot set horizontal margin when setting left/right'
|
129
|
+
elsif vert && (top || bottom)
|
130
|
+
raise ArgumentError, 'Cannot set vertical margin when setting top/bottom'
|
131
|
+
end
|
132
|
+
|
133
|
+
if horiz
|
134
|
+
margin.horiz = horiz
|
135
|
+
else
|
136
|
+
margin.left = left if left
|
137
|
+
margin.right = right if right
|
138
|
+
end
|
139
|
+
|
140
|
+
if vert
|
141
|
+
margin.vert = vert
|
142
|
+
else
|
143
|
+
margin.top = top if top
|
144
|
+
margin.bottom = bottom if bottom
|
145
|
+
end
|
88
146
|
end
|
89
147
|
|
90
148
|
def margin
|
91
|
-
@_margin
|
149
|
+
@_margin ||= Margin.new
|
92
150
|
end
|
93
151
|
|
94
|
-
def set_padding(left: nil, top: nil, right: nil, bottom: nil)
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
152
|
+
def set_padding(left: nil, top: nil, right: nil, bottom: nil, horiz: nil, vert: nil)
|
153
|
+
if horiz && (left || right)
|
154
|
+
raise ArgumentError, 'Cannot set horizontal padding when setting left/right'
|
155
|
+
elsif vert && (top || bottom)
|
156
|
+
raise ArgumentError, 'Cannot set vertical padding when setting top/bottom'
|
157
|
+
end
|
158
|
+
|
159
|
+
if horiz
|
160
|
+
padding.horiz = horiz
|
161
|
+
else
|
162
|
+
padding.left = left if left
|
163
|
+
padding.right = right if right
|
164
|
+
end
|
165
|
+
|
166
|
+
if vert
|
167
|
+
padding.vert = vert
|
168
|
+
else
|
169
|
+
padding.top = top if top
|
170
|
+
padding.bottom = bottom if bottom
|
171
|
+
end
|
100
172
|
end
|
101
173
|
|
102
174
|
def padding
|
103
|
-
@_padding
|
175
|
+
@_padding ||= Padding.new
|
104
176
|
end
|
105
177
|
|
106
178
|
def set_position(left: nil, top: nil)
|
107
|
-
|
108
|
-
|
109
|
-
@_position.top = top if top
|
179
|
+
position.left = left if left
|
180
|
+
position.top = top if top
|
110
181
|
end
|
111
182
|
|
112
183
|
def position
|
113
|
-
@_position
|
184
|
+
@_position ||= Position.new
|
114
185
|
end
|
115
186
|
|
116
187
|
def set_scrollbar(horiz: nil, vert: nil)
|
117
|
-
|
118
|
-
|
119
|
-
@_scrollbar.vert = vert unless vert.nil?
|
188
|
+
scrollbar.horiz = horiz unless horiz.nil?
|
189
|
+
scrollbar.vert = vert unless vert.nil?
|
120
190
|
end
|
121
191
|
|
122
192
|
def scrollbar
|
123
|
-
@_scrollbar
|
193
|
+
@_scrollbar ||= Scrollbar.new
|
194
|
+
end
|
195
|
+
|
196
|
+
def sizing
|
197
|
+
@_sizing || Sizing::DEFAULT
|
198
|
+
end
|
199
|
+
|
200
|
+
def border_sizing?
|
201
|
+
@_sizing == Sizing::BORDER
|
202
|
+
end
|
203
|
+
|
204
|
+
def content_sizing?
|
205
|
+
@_sizing == Sizing::CONTENT
|
206
|
+
end
|
207
|
+
|
208
|
+
def sizing=(sizing)
|
209
|
+
@_sizing = Sizing.validate!(sizing)
|
124
210
|
end
|
125
211
|
|
126
212
|
def inherit(parent)
|
127
213
|
super
|
128
214
|
return unless parent.is_a?(ContainerSettings)
|
129
|
-
@_align = parent._align
|
130
|
-
@_flow = parent._flow
|
131
215
|
set_border(color: parent.border.color, style: parent.border.style)
|
132
216
|
end
|
133
217
|
|
134
218
|
protected
|
135
|
-
|
136
|
-
attr_accessor :_align, :_flow
|
137
219
|
end
|
138
220
|
end
|
139
221
|
end
|