whirled_peas 0.5.0 → 0.6.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 (96) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/CHANGELOG.md +6 -0
  4. data/README.md +62 -29
  5. data/Rakefile +3 -2
  6. data/examples/intro.rb +52 -0
  7. data/examples/scrolling.rb +53 -0
  8. data/lib/whirled_peas.rb +2 -8
  9. data/lib/whirled_peas/command_line.rb +25 -33
  10. data/lib/whirled_peas/graphics/box_painter.rb +9 -1
  11. data/lib/whirled_peas/graphics/composer.rb +80 -0
  12. data/lib/whirled_peas/graphics/container_coords.rb +18 -8
  13. data/lib/whirled_peas/graphics/container_dimensions.rb +17 -7
  14. data/lib/whirled_peas/graphics/container_painter.rb +151 -33
  15. data/lib/whirled_peas/graphics/debugger.rb +10 -1
  16. data/lib/whirled_peas/graphics/grid_painter.rb +14 -2
  17. data/lib/whirled_peas/graphics/mock_screen.rb +1 -1
  18. data/lib/whirled_peas/graphics/painter.rb +1 -6
  19. data/lib/whirled_peas/graphics/renderer.rb +1 -29
  20. data/lib/whirled_peas/graphics/screen.rb +8 -3
  21. data/lib/whirled_peas/graphics/text_painter.rb +6 -4
  22. data/lib/whirled_peas/settings/container_settings.rb +11 -0
  23. data/lib/whirled_peas/settings/debugger.rb +9 -0
  24. data/lib/whirled_peas/settings/grid_settings.rb +4 -0
  25. data/lib/whirled_peas/settings/scrollbar.rb +15 -0
  26. data/lib/whirled_peas/version.rb +1 -1
  27. data/screen_test/rendered/elements/box.frame +1 -1
  28. data/screen_test/rendered/elements/grid.frame +1 -1
  29. data/screen_test/rendered/elements/screen_overflow.frame +1 -0
  30. data/screen_test/rendered/elements/text.frame +1 -1
  31. data/screen_test/rendered/elements/text_multiline.frame +1 -1
  32. data/screen_test/rendered/settings/align/box.frame +1 -1
  33. data/screen_test/rendered/settings/align/box.rb +14 -10
  34. data/screen_test/rendered/settings/align/children_center.frame +1 -1
  35. data/screen_test/rendered/settings/align/children_left.frame +1 -1
  36. data/screen_test/rendered/settings/align/children_right.frame +1 -1
  37. data/screen_test/rendered/settings/align/grid.frame +1 -1
  38. data/screen_test/rendered/settings/ansi/bold.frame +1 -1
  39. data/screen_test/rendered/settings/ansi/color.frame +1 -1
  40. data/screen_test/rendered/settings/ansi/underline.frame +1 -1
  41. data/screen_test/rendered/settings/border.frame +1 -1
  42. data/screen_test/rendered/settings/flow/box_b2t.frame +1 -0
  43. data/screen_test/rendered/settings/flow/box_b2t.rb +24 -0
  44. data/screen_test/rendered/settings/flow/{l2r.frame → box_l2r.frame} +1 -1
  45. data/screen_test/rendered/settings/flow/{l2r.rb → box_l2r.rb} +0 -0
  46. data/screen_test/rendered/settings/flow/box_r2l.frame +1 -0
  47. data/screen_test/rendered/settings/flow/box_r2l.rb +24 -0
  48. data/screen_test/rendered/settings/flow/{t2b.frame → box_t2b.frame} +1 -1
  49. data/screen_test/rendered/settings/flow/{t2b.rb → box_t2b.rb} +0 -0
  50. data/screen_test/rendered/settings/flow/grid_b2t.frame +1 -0
  51. data/screen_test/rendered/settings/flow/grid_b2t.rb +14 -0
  52. data/screen_test/rendered/settings/flow/grid_l2r.frame +1 -0
  53. data/screen_test/rendered/settings/flow/grid_l2r.rb +14 -0
  54. data/screen_test/rendered/settings/flow/grid_r2l.frame +1 -0
  55. data/screen_test/rendered/settings/flow/grid_r2l.rb +14 -0
  56. data/screen_test/rendered/settings/flow/grid_t2b.frame +1 -0
  57. data/screen_test/rendered/settings/flow/grid_t2b.rb +14 -0
  58. data/screen_test/rendered/settings/height/box.frame +1 -1
  59. data/screen_test/rendered/settings/height/grid.frame +1 -1
  60. data/screen_test/rendered/settings/height/overflow_box.frame +1 -1
  61. data/screen_test/rendered/settings/height/overflow_box_l2r.frame +1 -1
  62. data/screen_test/rendered/settings/height/overflow_box_t2b.frame +1 -1
  63. data/screen_test/rendered/settings/height/overflow_grid.frame +1 -1
  64. data/screen_test/rendered/settings/margin.frame +1 -1
  65. data/screen_test/rendered/settings/padding.frame +1 -1
  66. data/screen_test/rendered/settings/position/box_left.frame +1 -1
  67. data/screen_test/rendered/settings/position/box_left_negative.frame +1 -1
  68. data/screen_test/rendered/settings/position/box_top.frame +1 -1
  69. data/screen_test/rendered/settings/position/box_top_negative.frame +1 -1
  70. data/screen_test/rendered/settings/position/grid_left.frame +1 -1
  71. data/screen_test/rendered/settings/position/grid_left_negative.frame +1 -1
  72. data/screen_test/rendered/settings/position/grid_top.frame +1 -1
  73. data/screen_test/rendered/settings/position/grid_top_negative.frame +1 -1
  74. data/screen_test/rendered/settings/scroll/horiz_box.frame +1 -0
  75. data/screen_test/rendered/settings/scroll/horiz_box.rb +15 -0
  76. data/screen_test/rendered/settings/scroll/vert_box.frame +1 -0
  77. data/screen_test/rendered/settings/scroll/vert_box.rb +18 -0
  78. data/screen_test/rendered/settings/title_font.frame +1 -1
  79. data/screen_test/rendered/settings/width/box.frame +1 -1
  80. data/screen_test/rendered/settings/width/grid.frame +1 -1
  81. data/screen_test/rendered/settings/width/overflow_box.frame +1 -1
  82. data/screen_test/rendered/settings/width/overflow_box_l2r.frame +1 -1
  83. data/screen_test/rendered/settings/width/overflow_box_t2b.frame +1 -1
  84. data/screen_test/rendered/settings/width/overflow_grid.frame +1 -1
  85. data/screen_test/screen_tester.rb +13 -3
  86. metadata +27 -16
  87. data/bin/debug +0 -35
  88. data/lib/whirled_peas/debugger.rb +0 -80
  89. data/lib/whirled_peas/template.rb +0 -5
  90. data/lib/whirled_peas/template/box_element.rb +0 -8
  91. data/lib/whirled_peas/template/composer.rb +0 -68
  92. data/lib/whirled_peas/template/container.rb +0 -28
  93. data/lib/whirled_peas/template/debugger.rb +0 -34
  94. data/lib/whirled_peas/template/element.rb +0 -13
  95. data/lib/whirled_peas/template/grid_element.rb +0 -8
  96. data/lib/whirled_peas/template/text_element.rb +0 -24
@@ -7,7 +7,7 @@ module WhirledPeas
7
7
  def paint(canvas, &block)
8
8
  super
9
9
  return unless canvas.writable?
10
- if element.settings.horizontal_flow?
10
+ if settings.horizontal_flow?
11
11
  paint_horizontally(canvas, &block)
12
12
  else
13
13
  paint_vertically(canvas, &block)
@@ -37,6 +37,14 @@ module WhirledPeas
37
37
  end
38
38
  end
39
39
 
40
+ def each_child(&block)
41
+ if settings.reverse_flow?
42
+ children.reverse.each(&block)
43
+ else
44
+ super
45
+ end
46
+ end
47
+
40
48
  private
41
49
 
42
50
  def paint_horizontally(canvas, &block)
@@ -0,0 +1,80 @@
1
+ require 'whirled_peas/settings/box_settings'
2
+ require 'whirled_peas/settings/grid_settings'
3
+ require 'whirled_peas/settings/text_settings'
4
+
5
+ require_relative 'box_painter'
6
+ require_relative 'grid_painter'
7
+ require_relative 'text_painter'
8
+
9
+ module WhirledPeas
10
+ module Graphics
11
+ class Composer
12
+ # List of classes that convert nicely to a string
13
+ STRINGALBE_CLASSES = [FalseClass, Float, Integer, NilClass, String, Symbol, TrueClass]
14
+ private_constant :STRINGALBE_CLASSES
15
+
16
+ def self.stringable?(value)
17
+ STRINGALBE_CLASSES.include?(value.class)
18
+ end
19
+
20
+ def self.next_name
21
+ @counter ||= 0
22
+ @counter += 1
23
+ "Element-#{@counter}"
24
+ end
25
+
26
+ def self.build
27
+ settings = Settings::BoxSettings.new
28
+ template = BoxPainter.new('TEMPLATE', settings)
29
+ composer = Composer.new(template)
30
+ value = yield composer, settings
31
+ if !template.children? && stringable?(value)
32
+ composer.add_text { value.to_s }
33
+ end
34
+ template
35
+ end
36
+
37
+ attr_reader :painter
38
+
39
+ def initialize(painter)
40
+ @painter = painter
41
+ end
42
+
43
+ def add_text(name=self.class.next_name, &block)
44
+ child_settings = Settings::TextSettings.inherit(painter.settings)
45
+ child = TextPainter.new(name, child_settings)
46
+ # TextPainters are not composable, so yield nil
47
+ content = yield nil, child_settings
48
+ unless self.class.stringable?(content)
49
+ raise ArgumentError, "Unsupported type for text: #{content.class}"
50
+ end
51
+ child.content = content.to_s
52
+ painter.add_child(child)
53
+ end
54
+
55
+ def add_box(name=self.class.next_name, &block)
56
+ child_settings = Settings::BoxSettings.inherit(painter.settings)
57
+ child = BoxPainter.new(name, child_settings)
58
+ composer = self.class.new(child)
59
+ value = yield composer, child.settings
60
+ painter.add_child(child)
61
+ if !child.children? && self.class.stringable?(value)
62
+ composer.add_text("#{name}-Text") { value.to_s }
63
+ end
64
+ end
65
+
66
+ def add_grid(name=self.class.next_name, &block)
67
+ child_settings = Settings::GridSettings.inherit(painter.settings)
68
+ child = GridPainter.new(name, child_settings)
69
+ composer = self.class.new(child)
70
+ values = yield composer, child.settings
71
+ painter.add_child(child)
72
+ if !child.children? && values.is_a?(Array)
73
+ values.each.with_index do |value, index|
74
+ composer.add_text("#{name}-Text-#{index}") { value.to_s }
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -32,27 +32,37 @@ module WhirledPeas
32
32
  end
33
33
 
34
34
  def content_left(col_index=0)
35
- padding_left + settings.padding.left + col_index * grid_width(true)
35
+ padding_left + settings.padding.left + col_index * grid_width
36
36
  end
37
37
 
38
38
  def content_top(row_index=0)
39
- padding_top + settings.padding.top + row_index * grid_height(true)
39
+ padding_top + settings.padding.top + row_index * grid_height
40
40
  end
41
41
 
42
- def grid_width(include_border)
43
- (include_border && settings.border.inner_vert? ? 1 : 0) +
44
- settings.padding.left +
42
+ def inner_grid_width
43
+ settings.padding.left +
45
44
  dimensions.content_width +
46
45
  settings.padding.right
47
46
  end
48
47
 
49
- def grid_height(include_border)
50
- (include_border && settings.border.inner_horiz? ? 1 : 0) +
51
- settings.padding.top +
48
+ def grid_width
49
+ (settings.border.inner_vert? ? 1 : 0) +
50
+ inner_grid_width +
51
+ (settings.scrollbar.vert? ? 1 : 0)
52
+ end
53
+
54
+ def inner_grid_height
55
+ settings.padding.top +
52
56
  dimensions.content_height +
53
57
  settings.padding.bottom
54
58
  end
55
59
 
60
+ def grid_height
61
+ (settings.border.inner_horiz? ? 1 : 0) +
62
+ inner_grid_height +
63
+ (settings.scrollbar.horiz? ? 1 : 0)
64
+ end
65
+
56
66
  private
57
67
 
58
68
  attr_reader :canvas, :settings, :dimensions
@@ -1,11 +1,13 @@
1
1
  module WhirledPeas
2
2
  module Graphics
3
3
  class ContainerDimensions
4
- attr_reader :content_width, :content_height, :num_cols, :num_rows
4
+ attr_reader :content_width, :content_height, :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
7
  @content_width = settings.width || content_width
8
8
  @content_height = settings.height || content_height
9
+ @children_width = content_width
10
+ @children_height = content_height
9
11
  @num_cols = num_cols
10
12
  @num_rows = num_rows
11
13
  @settings = settings
@@ -14,21 +16,17 @@ module WhirledPeas
14
16
  def outer_width
15
17
  @outer_width ||= margin_width +
16
18
  outer_border_width +
17
- num_cols * (padding_width + content_width) +
19
+ num_cols * (padding_width + content_width + vert_scroll_width) +
18
20
  (num_cols - 1) * inner_border_width
19
21
  end
20
22
 
21
23
  def outer_height
22
24
  @outer_height ||= margin_height +
23
25
  outer_border_height +
24
- num_rows * (padding_height + content_height) +
26
+ num_rows * (padding_height + content_height + horiz_scroll_height) +
25
27
  (num_rows - 1) * inner_border_height
26
28
  end
27
29
 
28
- private
29
-
30
- attr_reader :settings
31
-
32
30
  def margin_width
33
31
  settings.margin.left + settings.margin.right
34
32
  end
@@ -60,6 +58,18 @@ module WhirledPeas
60
58
  def padding_height
61
59
  settings.padding.top + settings.padding.bottom
62
60
  end
61
+
62
+ def vert_scroll_width
63
+ settings.scrollbar.vert? ? 1 : 0
64
+ end
65
+
66
+ def horiz_scroll_height
67
+ settings.scrollbar.horiz? ? 1 : 0
68
+ end
69
+
70
+ private
71
+
72
+ attr_reader :settings
63
73
  end
64
74
  end
65
75
  end
@@ -8,38 +8,39 @@ module WhirledPeas
8
8
  class ContainerPainter < Painter
9
9
  PADDING = ' '
10
10
 
11
- def initialize(element, settings, name)
11
+ def initialize(name, settings)
12
12
  super
13
13
  @children = []
14
14
  end
15
15
 
16
16
  def paint(canvas, &block)
17
17
  return unless canvas.writable?
18
- has_inner_vert = dimensions.num_cols > 1 && settings.border.inner_vert?
19
- has_inner_horiz = dimensions.num_rows > 1 && settings.border.inner_horiz?
20
- has_border = settings.border.outer? || has_inner_vert || has_inner_horiz
21
- return unless settings.bg_color || has_border
22
- stroke_left = coords(canvas).border_left
23
- stroke_top = coords(canvas).border_top
18
+ return unless needs_printing?
19
+ canvas_coords = coords(canvas)
20
+ stroke_left = canvas_coords.border_left
21
+ stroke_top = canvas_coords.border_top
24
22
  formatting = [*settings.border.color, *settings.bg_color]
25
23
  if settings.border.top?
26
- canvas.stroke(stroke_left, stroke_top, top_border_stroke, formatting, &block)
24
+ canvas.stroke(stroke_left, stroke_top, top_border_stroke(canvas_coords), formatting, &block)
27
25
  stroke_top += 1
28
26
  end
29
- content_line = content_line_stroke
30
- middle_border = dimensions.num_rows > 1 ? middle_border_stroke : ''
27
+ middle_border = dimensions.num_rows > 1 ? middle_border_stroke(canvas_coords) : ''
31
28
  dimensions.num_rows.times do |row_num|
32
29
  if row_num > 0 && settings.border.inner_horiz?
33
30
  canvas.stroke(stroke_left, stroke_top, middle_border, formatting, &block)
34
31
  stroke_top += 1
35
32
  end
36
- coords(canvas).grid_height(false).times do
37
- canvas.stroke(stroke_left, stroke_top, content_line, formatting, &block)
33
+ canvas_coords.inner_grid_height.times do |row_within_cell|
34
+ canvas.stroke(stroke_left, stroke_top, content_line_stroke(canvas_coords, row_within_cell), formatting, &block)
35
+ stroke_top += 1
36
+ end
37
+ if settings.scrollbar.horiz?
38
+ canvas.stroke(stroke_left, stroke_top, bottom_scroll_stroke(canvas_coords), formatting, &block)
38
39
  stroke_top += 1
39
40
  end
40
41
  end
41
42
  if settings.border.bottom?
42
- canvas.stroke(stroke_left, stroke_top, bottom_border_stroke, formatting, &block)
43
+ canvas.stroke(stroke_left, stroke_top, bottom_border_stroke(canvas_coords), formatting, &block)
43
44
  stroke_top += 1
44
45
  end
45
46
  end
@@ -52,6 +53,10 @@ module WhirledPeas
52
53
  children.length
53
54
  end
54
55
 
56
+ def children?
57
+ num_children > 0
58
+ end
59
+
55
60
  def each_child(&block)
56
61
  children.each(&block)
57
62
  end
@@ -60,55 +65,168 @@ module WhirledPeas
60
65
 
61
66
  attr_reader :children
62
67
 
68
+ def needs_printing?
69
+ return true if settings.bg_color
70
+ return true if settings.border.outer?
71
+ return true if dimensions.num_cols > 1 && settings.border.inner_vert?
72
+ return true if dimensions.num_rows > 1 && settings.border.inner_horiz?
73
+ settings.scrollbar.horiz? || settings.scrollbar.vert?
74
+ end
75
+
63
76
  def coords(canvas)
64
77
  ContainerCoords.new(canvas, dimensions, settings)
65
78
  end
66
79
 
67
- def line_stroke(left_border, horiz_border, junc_border, right_border)
80
+ def line_stroke(left_border, junc_border, right_border, &block)
68
81
  stroke = ''
69
82
  stroke += left_border if settings.border.left?
70
83
  dimensions.num_cols.times do |col_num|
71
84
  stroke += junc_border if col_num > 0 && settings.border.inner_vert?
72
- stroke += horiz_border * (dimensions.content_width + settings.padding.left + settings.padding.right)
85
+ stroke += yield
73
86
  end
74
87
  stroke += right_border if settings.border.right?
75
88
  stroke
76
89
  end
77
90
 
78
- def top_border_stroke
91
+ def top_border_stroke(canvas_coords)
79
92
  line_stroke(
80
93
  settings.border.style.top_left,
81
- settings.border.style.top_horiz,
82
94
  settings.border.style.top_junc,
83
95
  settings.border.style.top_right
84
- )
85
- end
86
-
87
- def content_line_stroke
88
- line_stroke(
89
- settings.border.style.left_vert,
90
- PADDING,
91
- settings.border.style.middle_vert,
92
- settings.border.style.right_vert
93
- )
96
+ ) do
97
+ settings.border.style.top_horiz * (canvas_coords.inner_grid_width + (settings.scrollbar.vert? ? 1 : 0))
98
+ end
94
99
  end
95
100
 
96
- def middle_border_stroke
101
+ def middle_border_stroke(canvas_coords)
97
102
  line_stroke(
98
103
  settings.border.style.left_junc,
99
- settings.border.style.middle_horiz,
100
104
  settings.border.style.cross_junc,
101
105
  settings.border.style.right_junc
102
- )
106
+ ) do
107
+ settings.border.style.middle_horiz * (canvas_coords.inner_grid_width + (settings.scrollbar.vert? ? 1 : 0))
108
+ end
103
109
  end
104
110
 
105
- def bottom_border_stroke
111
+ def bottom_border_stroke(canvas_coords)
106
112
  line_stroke(
107
113
  settings.border.style.bottom_left,
108
- settings.border.style.bottom_horiz,
109
114
  settings.border.style.bottom_junc,
110
115
  settings.border.style.bottom_right
111
- )
116
+ ) do
117
+ settings.border.style.bottom_horiz * (canvas_coords.inner_grid_width + (settings.scrollbar.vert? ? 1 : 0))
118
+ end
119
+ end
120
+
121
+ def content_line_stroke(canvas_coords, row_within_cell)
122
+ line_stroke(
123
+ settings.border.style.left_vert,
124
+ settings.border.style.middle_vert,
125
+ settings.border.style.right_vert,
126
+ ) do
127
+ if settings.scrollbar.vert?
128
+ if dimensions.children_height <= canvas_coords.grid_height || children.first.settings.position.top > 0
129
+ scrollbar_char = GUTTER
130
+ else
131
+ scrollbar_char = vert_scroll_char(
132
+ dimensions.children_height + dimensions.padding_height,
133
+ canvas_coords.inner_grid_height,
134
+ -children.first.settings.position.top,
135
+ row_within_cell
136
+ )
137
+ end
138
+ PADDING * canvas_coords.inner_grid_width + scrollbar_char
139
+ else
140
+ PADDING * canvas_coords.inner_grid_width
141
+ end
142
+ end
143
+ end
144
+
145
+ def bottom_scroll_stroke(canvas_coords)
146
+ line_stroke(
147
+ settings.border.style.left_vert,
148
+ settings.border.style.middle_vert,
149
+ settings.border.style.right_vert,
150
+ ) do
151
+ canvas_coords.inner_grid_width.times.map do |col_within_cell|
152
+ horiz_scroll_char(
153
+ dimensions.children_width + dimensions.padding_width,
154
+ canvas_coords.inner_grid_width,
155
+ -children.first.settings.position.left,
156
+ col_within_cell
157
+ )
158
+ end.join
159
+ end
160
+ end
161
+
162
+ GUTTER = ' '
163
+ HORIZONTAL = %w[▗ ▄ ▖]
164
+ VERTICAL = %w[
165
+
166
+
167
+
168
+ ]
169
+
170
+ def horiz_scroll_char(col_count, viewable_col_count, first_visible_col, curr_col)
171
+ scroll_char(col_count, viewable_col_count, first_visible_col, curr_col, HORIZONTAL)
172
+ end
173
+
174
+ def vert_scroll_char(row_count, viewable_row_count, first_visible_row, curr_row)
175
+ scroll_char(row_count, viewable_row_count, first_visible_row, curr_row, VERTICAL)
176
+ end
177
+
178
+ private
179
+
180
+ def scroll_char(total_count, viewable_count, first_visible, curr, chars)
181
+ return GUTTER unless total_count > 0 && viewable_count > 0
182
+ # The scroll handle has the exact same relative size and position in the scroll gutter
183
+ # that the viewable content has in the total content area. For example, a content area
184
+ # that is 50 columns wide with a view port that is 20 columns wide might look like
185
+ #
186
+ # +---------1-----****2*********3******---4---------+
187
+ # | * * |
188
+ # | hidden * viewable * hidden |
189
+ # | * * |
190
+ # +---------1-----****2*********3******---4---------+
191
+ #
192
+ # The scoll gutter, would look like
193
+ #
194
+ # |......********.....|
195
+ #
196
+ # Scrolling all the way to the right results in
197
+ #
198
+ # +---------1---------2---------3*********4*********+
199
+ # | * *
200
+ # | hidden * viewable *
201
+ # | * *
202
+ # +---------1---------2---------3*********4*********+
203
+ # |...........********|
204
+
205
+ # The first task of determining how much of the handle is visible in a row/column is to
206
+ # calculate the range (as a precentage of the total) of viewable items
207
+ viewable_start = first_visible.to_f / total_count
208
+ viewable_end = (first_visible + viewable_count).to_f / total_count
209
+
210
+ # Always use the same length for the scroll bar so it does not give an inchworm effect
211
+ # as it scrolls along.
212
+ #
213
+ # Also, double the value now to get granularity for half width
214
+ # scrollbar characters.
215
+ scrollbar_length = ((2 * viewable_count ** 2).to_f / total_count).ceil
216
+ scrollbar_start = ((2 * first_visible * viewable_count).to_f / total_count).floor
217
+
218
+ first_half = (scrollbar_start...scrollbar_start + scrollbar_length).include?(2 * curr)
219
+ second_half = (scrollbar_start...scrollbar_start + scrollbar_length).include?(2 * curr + 1)
220
+
221
+ if first_half && second_half
222
+ chars[1]
223
+ elsif first_half
224
+ chars[2]
225
+ elsif second_half
226
+ chars[0]
227
+ else
228
+ GUTTER
229
+ end
112
230
  end
113
231
  end
114
232
  private_constant :ContainerPainter