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
@@ -4,28 +4,29 @@ module WhirledPeas
|
|
4
4
|
module Graphics
|
5
5
|
# Canvas represent the area of the screen a painter can paint on.
|
6
6
|
class Canvas
|
7
|
-
attr_reader :left, :top, :width, :height
|
7
|
+
attr_reader :left, :top, :width, :height
|
8
8
|
|
9
9
|
def self.unwritable
|
10
|
-
new(-1, -1, 0, 0
|
10
|
+
new(-1, -1, 0, 0)
|
11
11
|
end
|
12
12
|
|
13
|
-
def initialize(left, top, width, height
|
13
|
+
def initialize(left, top, width, height)
|
14
14
|
@left = left
|
15
15
|
@top = top
|
16
16
|
@width = width
|
17
17
|
@height = height
|
18
|
-
@start_left = start_left
|
19
|
-
@start_top = start_top
|
20
18
|
end
|
21
19
|
|
22
20
|
def writable?
|
23
21
|
width > 0 || height > 0
|
24
22
|
end
|
25
23
|
|
26
|
-
def child(
|
27
|
-
|
28
|
-
|
24
|
+
def child(child_left, child_top, child_width, child_height)
|
25
|
+
Graphics.debugger(
|
26
|
+
proc do
|
27
|
+
"Create child: #{self.inspect}.child(left=#{child_left}, top=#{child_top}, width=#{child_width}, height=#{child_height})"
|
28
|
+
end
|
29
|
+
)
|
29
30
|
if child_left >= left + width
|
30
31
|
self.class.unwritable
|
31
32
|
elsif child_left + child_width <= left
|
@@ -45,20 +46,25 @@ module WhirledPeas
|
|
45
46
|
child_top = top
|
46
47
|
end
|
47
48
|
child_height = [height - (child_top - top), child_height].min
|
48
|
-
self.class.new(
|
49
|
+
child_canvas = self.class.new(
|
49
50
|
child_left,
|
50
51
|
child_top,
|
51
52
|
child_width,
|
52
53
|
child_height,
|
53
|
-
start_left,
|
54
|
-
start_top
|
55
54
|
)
|
55
|
+
Graphics.debugger(proc { " -> #{child_canvas.inspect}" })
|
56
|
+
child_canvas
|
56
57
|
end
|
57
58
|
end
|
58
59
|
|
59
60
|
# Yields a single line of formatted characters positioned on the canvas,
|
60
61
|
# verifying only characters within the canvas are included.
|
61
62
|
def stroke(stroke_left, stroke_top, raw, formatting=[], &block)
|
63
|
+
Graphics.debugger(
|
64
|
+
proc do
|
65
|
+
"Stroke: #{self.inspect}.stroke(left=#{stroke_left}, top=#{stroke_top}, length=#{raw.length})"
|
66
|
+
end
|
67
|
+
)
|
62
68
|
if stroke_left >= left + width
|
63
69
|
# The stroke starts to the right of the canvas
|
64
70
|
fstring = Utils::FormattedString.blank
|
@@ -88,6 +94,11 @@ module WhirledPeas
|
|
88
94
|
end_index = start_index + visible_length - 1
|
89
95
|
fstring = Utils::FormattedString.new(raw[start_index..end_index], formatting)
|
90
96
|
end
|
97
|
+
Graphics.debugger(
|
98
|
+
proc do
|
99
|
+
" -> Stroke(left=#{stroke_left}, top=#{stroke_top}, length=#{fstring.length})"
|
100
|
+
end
|
101
|
+
)
|
91
102
|
yield stroke_left, stroke_top, fstring
|
92
103
|
end
|
93
104
|
|
@@ -1,8 +1,10 @@
|
|
1
1
|
require 'whirled_peas/settings/box_settings'
|
2
|
+
require 'whirled_peas/settings/graph_settings'
|
2
3
|
require 'whirled_peas/settings/grid_settings'
|
3
4
|
require 'whirled_peas/settings/text_settings'
|
4
5
|
|
5
6
|
require_relative 'box_painter'
|
7
|
+
require_relative 'graph_painter'
|
6
8
|
require_relative 'grid_painter'
|
7
9
|
require_relative 'text_painter'
|
8
10
|
|
@@ -45,6 +47,7 @@ module WhirledPeas
|
|
45
47
|
child = TextPainter.new(name, child_settings)
|
46
48
|
# TextPainters are not composable, so yield nil
|
47
49
|
content = yield nil, child_settings
|
50
|
+
child_settings.validate!
|
48
51
|
unless self.class.stringable?(content)
|
49
52
|
raise ArgumentError, "Unsupported type for text: #{content.class}"
|
50
53
|
end
|
@@ -52,11 +55,25 @@ module WhirledPeas
|
|
52
55
|
painter.add_child(child)
|
53
56
|
end
|
54
57
|
|
58
|
+
def add_graph(name=self.class.next_name, &block)
|
59
|
+
child_settings = Settings::GraphSettings.inherit(painter.settings)
|
60
|
+
child = GraphPainter.new(name, child_settings)
|
61
|
+
# GraphPainters are not composable, so yield nil
|
62
|
+
content = yield nil, child_settings
|
63
|
+
child_settings.validate!
|
64
|
+
unless content.is_a?(Array) && content.length > 0
|
65
|
+
raise ArgumentError, 'Graphs require a non-empty array as the content'
|
66
|
+
end
|
67
|
+
child.content = content
|
68
|
+
painter.add_child(child)
|
69
|
+
end
|
70
|
+
|
55
71
|
def add_box(name=self.class.next_name, &block)
|
56
72
|
child_settings = Settings::BoxSettings.inherit(painter.settings)
|
57
73
|
child = BoxPainter.new(name, child_settings)
|
58
74
|
composer = self.class.new(child)
|
59
75
|
value = yield composer, child.settings
|
76
|
+
child_settings.validate!
|
60
77
|
painter.add_child(child)
|
61
78
|
if !child.children? && self.class.stringable?(value)
|
62
79
|
composer.add_text("#{name}-Text") { value.to_s }
|
@@ -68,6 +85,7 @@ module WhirledPeas
|
|
68
85
|
child = GridPainter.new(name, child_settings)
|
69
86
|
composer = self.class.new(child)
|
70
87
|
values = yield composer, child.settings
|
88
|
+
child_settings.validate!
|
71
89
|
painter.add_child(child)
|
72
90
|
if !child.children? && values.is_a?(Array)
|
73
91
|
values.each.with_index do |value, index|
|
@@ -1,18 +1,19 @@
|
|
1
1
|
module WhirledPeas
|
2
2
|
module Graphics
|
3
3
|
class ContainerCoords
|
4
|
-
def initialize(
|
5
|
-
@canvas = canvas
|
4
|
+
def initialize(dimensions, settings, start_left, start_top)
|
6
5
|
@dimensions = dimensions
|
7
6
|
@settings = settings
|
7
|
+
@start_left = start_left
|
8
|
+
@start_top = start_top
|
8
9
|
end
|
9
10
|
|
10
11
|
def left
|
11
|
-
|
12
|
+
start_left + settings.position.left
|
12
13
|
end
|
13
14
|
|
14
15
|
def top
|
15
|
-
|
16
|
+
start_top + settings.position.top
|
16
17
|
end
|
17
18
|
|
18
19
|
def border_left
|
@@ -65,7 +66,7 @@ module WhirledPeas
|
|
65
66
|
|
66
67
|
private
|
67
68
|
|
68
|
-
attr_reader :
|
69
|
+
attr_reader :settings, :dimensions, :start_left, :start_top
|
69
70
|
end
|
70
71
|
end
|
71
72
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
module WhirledPeas
|
2
2
|
module Graphics
|
3
3
|
class ContainerDimensions
|
4
|
-
attr_reader :
|
4
|
+
attr_reader :children_width, :children_height, :num_cols, :num_rows
|
5
5
|
|
6
6
|
def initialize(settings, content_width, content_height, num_cols=1, num_rows=1)
|
7
|
-
@
|
8
|
-
@
|
7
|
+
@orig_content_width = content_width
|
8
|
+
@orig_content_height = content_height
|
9
9
|
@children_width = content_width
|
10
10
|
@children_height = content_height
|
11
11
|
@num_cols = num_cols
|
@@ -13,17 +13,35 @@ module WhirledPeas
|
|
13
13
|
@settings = settings
|
14
14
|
end
|
15
15
|
|
16
|
+
def content_width
|
17
|
+
return orig_content_width unless settings.width
|
18
|
+
if settings.border_sizing?
|
19
|
+
settings.width - outer_border_width - scrollbar_width - padding_width
|
20
|
+
else
|
21
|
+
settings.width
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def content_height
|
26
|
+
return orig_content_height unless settings.height
|
27
|
+
if settings.border_sizing?
|
28
|
+
settings.height - outer_border_height - scrollbar_height - padding_height
|
29
|
+
else
|
30
|
+
settings.height
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
16
34
|
def outer_width
|
17
35
|
@outer_width ||= margin_width +
|
18
36
|
outer_border_width +
|
19
|
-
num_cols * (padding_width + content_width +
|
37
|
+
num_cols * (padding_width + content_width + scrollbar_width) +
|
20
38
|
(num_cols - 1) * inner_border_width
|
21
39
|
end
|
22
40
|
|
23
41
|
def outer_height
|
24
42
|
@outer_height ||= margin_height +
|
25
43
|
outer_border_height +
|
26
|
-
num_rows * (padding_height + content_height +
|
44
|
+
num_rows * (padding_height + content_height + scrollbar_height) +
|
27
45
|
(num_rows - 1) * inner_border_height
|
28
46
|
end
|
29
47
|
|
@@ -59,17 +77,17 @@ module WhirledPeas
|
|
59
77
|
settings.padding.top + settings.padding.bottom
|
60
78
|
end
|
61
79
|
|
62
|
-
def
|
80
|
+
def scrollbar_width
|
63
81
|
settings.scrollbar.vert? ? 1 : 0
|
64
82
|
end
|
65
83
|
|
66
|
-
def
|
84
|
+
def scrollbar_height
|
67
85
|
settings.scrollbar.horiz? ? 1 : 0
|
68
86
|
end
|
69
87
|
|
70
88
|
private
|
71
89
|
|
72
|
-
attr_reader :settings
|
90
|
+
attr_reader :settings, :orig_content_width, :orig_content_height
|
73
91
|
end
|
74
92
|
end
|
75
93
|
end
|
@@ -5,6 +5,8 @@ require_relative 'painter'
|
|
5
5
|
|
6
6
|
module WhirledPeas
|
7
7
|
module Graphics
|
8
|
+
# Abstract Painter for containers. Containers (as the name implies) contain other child
|
9
|
+
# elements and must delegate painting of the children to the children themselves.
|
8
10
|
class ContainerPainter < Painter
|
9
11
|
PADDING = ' '
|
10
12
|
|
@@ -13,38 +15,65 @@ module WhirledPeas
|
|
13
15
|
@children = []
|
14
16
|
end
|
15
17
|
|
16
|
-
|
18
|
+
# Paint the common attributes of containers (e.g. border and background color). Any
|
19
|
+
# class that inherits from this one should call `super` at the start of its #paint
|
20
|
+
# method, before painting its children.
|
21
|
+
def paint(canvas, left, top, &block)
|
17
22
|
return unless canvas.writable?
|
18
23
|
return unless needs_printing?
|
19
|
-
canvas_coords = coords(
|
24
|
+
canvas_coords = coords(left, top)
|
25
|
+
|
26
|
+
# Paint the border, background color, and scrollbar starting from the top left
|
27
|
+
# border position, moving down row by row until we reach the bottom border
|
28
|
+
# position
|
20
29
|
stroke_left = canvas_coords.border_left
|
21
30
|
stroke_top = canvas_coords.border_top
|
31
|
+
|
32
|
+
# All strokes will have the same formatting options
|
22
33
|
formatting = [*settings.border.color, *settings.bg_color]
|
34
|
+
|
35
|
+
# Paint the top border if the settings call for it
|
23
36
|
if settings.border.top?
|
24
37
|
canvas.stroke(stroke_left, stroke_top, top_border_stroke(canvas_coords), formatting, &block)
|
25
38
|
stroke_top += 1
|
26
39
|
end
|
40
|
+
# Precalculate the middle border container grids with more than 1 row
|
27
41
|
middle_border = dimensions.num_rows > 1 ? middle_border_stroke(canvas_coords) : ''
|
42
|
+
|
43
|
+
# Paint each grid row by row
|
28
44
|
dimensions.num_rows.times do |row_num|
|
45
|
+
# In a grid with N rows, we will need to paint N - 1 inner horizontal borders.
|
46
|
+
# This code treats the inner horizontal border as the top of each row except for
|
47
|
+
# the first one.
|
29
48
|
if row_num > 0 && settings.border.inner_horiz?
|
30
49
|
canvas.stroke(stroke_left, stroke_top, middle_border, formatting, &block)
|
31
50
|
stroke_top += 1
|
32
51
|
end
|
52
|
+
|
53
|
+
# Paint the interior of each row (horizontal borders, veritical scroll bar and
|
54
|
+
# background color for the padding and content area)
|
33
55
|
canvas_coords.inner_grid_height.times do |row_within_cell|
|
34
56
|
canvas.stroke(stroke_left, stroke_top, content_line_stroke(canvas_coords, row_within_cell), formatting, &block)
|
35
57
|
stroke_top += 1
|
36
58
|
end
|
59
|
+
|
60
|
+
# Paint the horizontal scroll bar is the settings call for it
|
37
61
|
if settings.scrollbar.horiz?
|
38
62
|
canvas.stroke(stroke_left, stroke_top, bottom_scroll_stroke(canvas_coords), formatting, &block)
|
39
63
|
stroke_top += 1
|
40
64
|
end
|
41
65
|
end
|
66
|
+
|
67
|
+
# Paint the bottom border if the settings call for it
|
42
68
|
if settings.border.bottom?
|
43
69
|
canvas.stroke(stroke_left, stroke_top, bottom_border_stroke(canvas_coords), formatting, &block)
|
44
70
|
stroke_top += 1
|
45
71
|
end
|
46
72
|
end
|
47
73
|
|
74
|
+
# Tightly manage access to the children (rather than simply exposing the underlying
|
75
|
+
# array). This allows subclasses to easily modify behavior based on that element's
|
76
|
+
# specific settings.
|
48
77
|
def add_child(child)
|
49
78
|
children << child
|
50
79
|
end
|
@@ -65,6 +94,8 @@ module WhirledPeas
|
|
65
94
|
|
66
95
|
attr_reader :children
|
67
96
|
|
97
|
+
# Determine if there is anything to print for the container (this does not accont for
|
98
|
+
# children, just the border, scrollbar, and background color)
|
68
99
|
def needs_printing?
|
69
100
|
return true if settings.bg_color
|
70
101
|
return true if settings.border.outer?
|
@@ -73,10 +104,66 @@ module WhirledPeas
|
|
73
104
|
settings.scrollbar.horiz? || settings.scrollbar.vert?
|
74
105
|
end
|
75
106
|
|
76
|
-
|
77
|
-
|
107
|
+
# Return an object that allows easy access to important coordinates within the container,
|
108
|
+
# e.g. the left position where the left border is printed
|
109
|
+
def coords(left, top)
|
110
|
+
ContainerCoords.new(dimensions, settings, left, top)
|
111
|
+
end
|
112
|
+
|
113
|
+
# @return [Array<Integer>] a two-item array, the first being the amount of horizontal
|
114
|
+
# spacing to paint *before the first* child and the second being the amount of spacing
|
115
|
+
# to paint *between each* child
|
116
|
+
def horiz_justify_offset(containing_width)
|
117
|
+
if settings.align_center?
|
118
|
+
[(dimensions.content_width - containing_width) / 2, 0]
|
119
|
+
elsif settings.align_right?
|
120
|
+
[dimensions.content_width - containing_width, 0]
|
121
|
+
elsif settings.align_between?
|
122
|
+
return [0, 0] if num_children == 1
|
123
|
+
[0, (dimensions.content_width - containing_width) / (num_children - 1)]
|
124
|
+
elsif settings.align_around?
|
125
|
+
full_spacing = (dimensions.content_width - containing_width) / num_children
|
126
|
+
[full_spacing / 2, full_spacing]
|
127
|
+
elsif settings.align_evenly?
|
128
|
+
spacing = (dimensions.content_width - containing_width) / (num_children + 1)
|
129
|
+
[spacing, spacing]
|
130
|
+
else
|
131
|
+
[0, 0]
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# @return [Array<Integer>] a two-item array, the first being the amount of vertical
|
136
|
+
# spacing to paint *above the first* child and the second being the amount of spacing
|
137
|
+
# to paint *between each* child
|
138
|
+
def vert_justify_offset(containing_height)
|
139
|
+
if settings.valign_middle?
|
140
|
+
[(dimensions.content_height - containing_height) / 2, 0]
|
141
|
+
elsif settings.valign_bottom?
|
142
|
+
[dimensions.content_height - containing_height, 0]
|
143
|
+
elsif settings.valign_between?
|
144
|
+
return [0, 0] if num_children == 1
|
145
|
+
[0, (dimensions.content_height - containing_height) / (num_children - 1)]
|
146
|
+
elsif settings.valign_around?
|
147
|
+
full_spacing = (dimensions.content_height - containing_height) / num_children
|
148
|
+
[full_spacing / 2, full_spacing]
|
149
|
+
elsif settings.valign_evenly?
|
150
|
+
spacing = (dimensions.content_height - containing_height) / (num_children + 1)
|
151
|
+
[spacing, spacing]
|
152
|
+
else
|
153
|
+
[0, 0]
|
154
|
+
end
|
78
155
|
end
|
79
156
|
|
157
|
+
# Return a stroke for one line of the container
|
158
|
+
#
|
159
|
+
# @param left_border [String] the character to print as the first character if there
|
160
|
+
# is a left border
|
161
|
+
# @param junc_border [String] the character to print as the junction between two grid
|
162
|
+
# columns if there is an inner vertical border
|
163
|
+
# @param right_border [String] the character to print as the last character if there
|
164
|
+
# is a right border
|
165
|
+
# @block [String] the block should yield a string that represents the interior
|
166
|
+
# (including padding) of a grid cell
|
80
167
|
def line_stroke(left_border, junc_border, right_border, &block)
|
81
168
|
stroke = ''
|
82
169
|
stroke += left_border if settings.border.left?
|
@@ -88,6 +175,7 @@ module WhirledPeas
|
|
88
175
|
stroke
|
89
176
|
end
|
90
177
|
|
178
|
+
# Return the stroke for the top border
|
91
179
|
def top_border_stroke(canvas_coords)
|
92
180
|
line_stroke(
|
93
181
|
settings.border.style.top_left,
|
@@ -98,6 +186,7 @@ module WhirledPeas
|
|
98
186
|
end
|
99
187
|
end
|
100
188
|
|
189
|
+
# Return the stroke for an inner horizontal border
|
101
190
|
def middle_border_stroke(canvas_coords)
|
102
191
|
line_stroke(
|
103
192
|
settings.border.style.left_junc,
|
@@ -108,6 +197,7 @@ module WhirledPeas
|
|
108
197
|
end
|
109
198
|
end
|
110
199
|
|
200
|
+
# Return the stroke for the bottom border
|
111
201
|
def bottom_border_stroke(canvas_coords)
|
112
202
|
line_stroke(
|
113
203
|
settings.border.style.bottom_left,
|
@@ -118,6 +208,7 @@ module WhirledPeas
|
|
118
208
|
end
|
119
209
|
end
|
120
210
|
|
211
|
+
# Return the stroke for a grid row between any borders
|
121
212
|
def content_line_stroke(canvas_coords, row_within_cell)
|
122
213
|
line_stroke(
|
123
214
|
settings.border.style.left_vert,
|
@@ -142,6 +233,7 @@ module WhirledPeas
|
|
142
233
|
end
|
143
234
|
end
|
144
235
|
|
236
|
+
# Return the stroke for the horizontal scroll bar
|
145
237
|
def bottom_scroll_stroke(canvas_coords)
|
146
238
|
line_stroke(
|
147
239
|
settings.border.style.left_vert,
|
@@ -159,6 +251,7 @@ module WhirledPeas
|
|
159
251
|
end
|
160
252
|
end
|
161
253
|
|
254
|
+
# Contants to paint scrollbars
|
162
255
|
GUTTER = ' '
|
163
256
|
HORIZONTAL = %w[▗ ▄ ▖]
|
164
257
|
VERTICAL = %w[
|
@@ -167,16 +260,33 @@ module WhirledPeas
|
|
167
260
|
▝
|
168
261
|
]
|
169
262
|
|
263
|
+
# Determine the character to paint the horizontal scroll bar with for the given column
|
264
|
+
#
|
265
|
+
# @see #scroll_char for more details
|
170
266
|
def horiz_scroll_char(col_count, viewable_col_count, first_visible_col, curr_col)
|
171
267
|
scroll_char(col_count, viewable_col_count, first_visible_col, curr_col, HORIZONTAL)
|
172
268
|
end
|
173
269
|
|
270
|
+
# Determine the character to paint the vertical scroll bar with for the given row
|
271
|
+
#
|
272
|
+
# @see #scroll_char for more details
|
174
273
|
def vert_scroll_char(row_count, viewable_row_count, first_visible_row, curr_row)
|
175
274
|
scroll_char(row_count, viewable_row_count, first_visible_row, curr_row, VERTICAL)
|
176
275
|
end
|
177
276
|
|
178
277
|
private
|
179
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.
|
180
290
|
def scroll_char(total_count, viewable_count, first_visible, curr, chars)
|
181
291
|
return GUTTER unless total_count > 0 && viewable_count > 0
|
182
292
|
# The scroll handle has the exact same relative size and position in the scroll gutter
|
@@ -201,6 +311,25 @@ module WhirledPeas
|
|
201
311
|
# | * *
|
202
312
|
# +---------1---------2---------3*********4*********+
|
203
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
|
204
333
|
|
205
334
|
# The first task of determining how much of the handle is visible in a row/column is to
|
206
335
|
# calculate the range (as a precentage of the total) of viewable items
|