whirled_peas 0.11.0 → 0.11.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -2
- data/CHANGELOG.md +5 -0
- data/README.md +7 -1156
- data/doc/application.md +92 -0
- data/doc/cli.md +115 -0
- data/doc/components.md +55 -0
- data/doc/easing.md +257 -0
- data/doc/elements.md +69 -0
- data/doc/screen_test.md +23 -0
- data/doc/settings.md +466 -0
- data/doc/template_factory.md +53 -0
- data/doc/themes.md +15 -0
- data/lib/data/themes.yaml +8 -4
- data/lib/whirled_peas/component/list_with_active.rb +3 -3
- data/lib/whirled_peas/graphics/container_coords.rb +2 -26
- data/lib/whirled_peas/graphics/container_dimensions.rb +24 -0
- data/lib/whirled_peas/graphics/container_painter.rb +26 -28
- data/lib/whirled_peas/graphics/debugger.rb +1 -0
- data/lib/whirled_peas/graphics/graph_painter.rb +31 -24
- data/lib/whirled_peas/graphics/scrollbar_helper.rb +31 -29
- data/lib/whirled_peas/settings/bg_color.rb +5 -1
- data/lib/whirled_peas/settings/border.rb +1 -1
- data/lib/whirled_peas/settings/color.rb +8 -4
- data/lib/whirled_peas/settings/debugger.rb +2 -0
- data/lib/whirled_peas/settings/element_settings.rb +10 -2
- data/lib/whirled_peas/settings/text_color.rb +5 -0
- data/lib/whirled_peas/settings/theme.rb +28 -7
- data/lib/whirled_peas/settings/theme_library.rb +10 -4
- data/lib/whirled_peas/version.rb +1 -1
- data/screen_test/components/list_with_active/l2r_position_start.frame +1 -1
- data/screen_test/components/list_with_active/l2r_separator.frame +1 -1
- data/screen_test/components/list_with_active/t2b_position_start.frame +1 -1
- data/screen_test/components/list_with_active/t2b_separator.frame +1 -1
- data/screen_test/elements/{graph.frame → graph_asc.frame} +1 -1
- data/screen_test/elements/{graph.rb → graph_asc.rb} +0 -0
- data/screen_test/elements/graph_desc.frame +1 -0
- data/screen_test/elements/graph_desc.rb +12 -0
- data/screen_test/elements/graph_horiz.frame +1 -0
- data/screen_test/elements/graph_horiz.rb +12 -0
- data/screen_test/elements/graph_sin.frame +1 -0
- data/screen_test/elements/graph_sin.rb +12 -0
- data/screen_test/elements/theme.frame +1 -1
- data/screen_test/settings/scroll/horiz_box.frame +1 -1
- data/screen_test/settings/scroll/vert_box.frame +1 -1
- metadata +19 -6
- data/bin/easing +0 -33
- data/lib/whirled_peas/graphics/mock_screen.rb +0 -26
@@ -0,0 +1,53 @@
|
|
1
|
+
## Template Factory
|
2
|
+
|
3
|
+
To render the frame events sent by the application, the application requires a template factory. This factory will be called for each frame event, with the frame name and the arguments supplied by the application. A template factory can be an instance of ruby class and thus can maintain state. Whirled Peas provides a few basic building blocks to make simple, yet elegant terminal-based UIs.
|
4
|
+
|
5
|
+
To build a template in a template factory, use `WhirledPeas.template(theme)`, which takes an optional [theme](themes.md) and yields a composer (used to add [elements](elements.md) to the template) and [settings](settings.md) (used to configure the element).
|
6
|
+
|
7
|
+
### Full example
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
class TemplateFactory
|
11
|
+
def build(frame, args)
|
12
|
+
set_state(frame, args)
|
13
|
+
WhirledPeas.template do |composer, settings|
|
14
|
+
settings.flow = :l2r
|
15
|
+
settings.align = :center
|
16
|
+
|
17
|
+
composer.add_box('Title', &method(:title))
|
18
|
+
composer.add_box('Sum', &method(:sum))
|
19
|
+
composer.add_grid('NumberGrid', &method(:number_grid))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def set_state(frame, args)
|
26
|
+
@frame = frame
|
27
|
+
@numbers = args.key?(:numbers) ? args[:numbers] || []
|
28
|
+
@sum = args[:sum] if args.key?(:sum)
|
29
|
+
@low = args[:low] if args.key?(:low)
|
30
|
+
@high = args[:high] if args.key?(:high)
|
31
|
+
end
|
32
|
+
|
33
|
+
def title(_composer, settings)
|
34
|
+
settings.underline = true
|
35
|
+
"Pair Finder"
|
36
|
+
end
|
37
|
+
|
38
|
+
def sum(_composer, settings)
|
39
|
+
settings.color = @frame == 'found-pair' ? :green : :red
|
40
|
+
@sum ? "Sum: #{@sum}" : 'N/A'
|
41
|
+
end
|
42
|
+
|
43
|
+
def number_grid(composer, settings)
|
44
|
+
settings.full_border
|
45
|
+
@numbers.each.with_index do |num, index|
|
46
|
+
composer.add_text do |_, settings|
|
47
|
+
settings.bg_color = (@low == index || @high == index) ? :cyan : :white
|
48
|
+
num
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
```
|
data/doc/themes.md
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
## Themes
|
2
|
+
|
3
|
+
The template builder (`WhirledPeas.template`) takes an optional `theme` argument. You can provide the name of a predefined theme (run `whirled_peas themes` to see a list with samples) or define you own with the following
|
4
|
+
|
5
|
+
```ruby
|
6
|
+
WhirledPeas.register_theme(:my_theme) do |theme|
|
7
|
+
theme.bg_color = :bright_white
|
8
|
+
theme.color = :blue
|
9
|
+
theme.border_color = :bright_green
|
10
|
+
theme.axis_color = :bright_red
|
11
|
+
theme.title_font = :default
|
12
|
+
end
|
13
|
+
```
|
14
|
+
|
15
|
+
Theme settings will be used as default settings throughout the template, however theme settings can be overridden on any element.
|
data/lib/data/themes.yaml
CHANGED
@@ -1,13 +1,17 @@
|
|
1
1
|
bright:
|
2
|
+
axis_color: :red
|
2
3
|
bg_color: :bright_white
|
3
|
-
color: :blue
|
4
4
|
border_color: :bright_blue
|
5
|
-
|
5
|
+
border_style: :soft
|
6
|
+
color: :blue
|
6
7
|
title_font: :default
|
7
8
|
|
8
9
|
dark:
|
10
|
+
axis_color: :bright_white
|
9
11
|
bg_color: :black
|
10
|
-
color: :white
|
11
12
|
border_color: :gray
|
12
|
-
|
13
|
+
border_style: :double
|
14
|
+
color: :white
|
15
|
+
highlight_bg_color: :bright_red
|
16
|
+
highlight_color: :black
|
13
17
|
title_font: :swan
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module WhirledPeas
|
2
2
|
module Component
|
3
3
|
class ListWithActive
|
4
|
-
attr_accessor :active_index, :
|
4
|
+
attr_accessor :active_index, :separator
|
5
5
|
|
6
6
|
attr_reader :items
|
7
7
|
|
@@ -75,8 +75,8 @@ module WhirledPeas
|
|
75
75
|
composer.add_text { separator } if !separator.nil? && index > 0
|
76
76
|
composer.add_text do |_, settings|
|
77
77
|
if index == active_index
|
78
|
-
settings.bg_color =
|
79
|
-
settings.color =
|
78
|
+
settings.bg_color = :highlight
|
79
|
+
settings.color = :highlight
|
80
80
|
end
|
81
81
|
item
|
82
82
|
end
|
@@ -33,7 +33,7 @@ module WhirledPeas
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def content_left(col_index=0)
|
36
|
-
padding_left + settings.padding.left + col_index * grid_width
|
36
|
+
padding_left + settings.padding.left + col_index * dimensions.grid_width
|
37
37
|
end
|
38
38
|
|
39
39
|
def offset_content_left(col_index=0)
|
@@ -48,7 +48,7 @@ module WhirledPeas
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def content_top(row_index=0)
|
51
|
-
padding_top + settings.padding.top + row_index * grid_height
|
51
|
+
padding_top + settings.padding.top + row_index * dimensions.grid_height
|
52
52
|
end
|
53
53
|
|
54
54
|
def offset_content_top(row_index=0)
|
@@ -62,30 +62,6 @@ module WhirledPeas
|
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
-
def inner_grid_width
|
66
|
-
settings.padding.left +
|
67
|
-
dimensions.content_width +
|
68
|
-
settings.padding.right
|
69
|
-
end
|
70
|
-
|
71
|
-
def grid_width
|
72
|
-
(settings.border.inner_vert? ? 1 : 0) +
|
73
|
-
inner_grid_width +
|
74
|
-
(settings.scrollbar.vert? ? 1 : 0)
|
75
|
-
end
|
76
|
-
|
77
|
-
def inner_grid_height
|
78
|
-
settings.padding.top +
|
79
|
-
dimensions.content_height +
|
80
|
-
settings.padding.bottom
|
81
|
-
end
|
82
|
-
|
83
|
-
def grid_height
|
84
|
-
(settings.border.inner_horiz? ? 1 : 0) +
|
85
|
-
inner_grid_height +
|
86
|
-
(settings.scrollbar.horiz? ? 1 : 0)
|
87
|
-
end
|
88
|
-
|
89
65
|
private
|
90
66
|
|
91
67
|
attr_reader :settings, :dimensions, :start_left, :start_top
|
@@ -31,6 +31,30 @@ module WhirledPeas
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
+
def inner_grid_width
|
35
|
+
settings.padding.left +
|
36
|
+
content_width +
|
37
|
+
settings.padding.right
|
38
|
+
end
|
39
|
+
|
40
|
+
def grid_width
|
41
|
+
(settings.border.inner_vert? ? 1 : 0) +
|
42
|
+
inner_grid_width +
|
43
|
+
(settings.scrollbar.vert? ? 1 : 0)
|
44
|
+
end
|
45
|
+
|
46
|
+
def inner_grid_height
|
47
|
+
settings.padding.top +
|
48
|
+
content_height +
|
49
|
+
settings.padding.bottom
|
50
|
+
end
|
51
|
+
|
52
|
+
def grid_height
|
53
|
+
(settings.border.inner_horiz? ? 1 : 0) +
|
54
|
+
inner_grid_height +
|
55
|
+
(settings.scrollbar.horiz? ? 1 : 0)
|
56
|
+
end
|
57
|
+
|
34
58
|
def outer_width
|
35
59
|
@outer_width ||= margin_width +
|
36
60
|
outer_border_width +
|
@@ -35,11 +35,17 @@ module WhirledPeas
|
|
35
35
|
|
36
36
|
# Paint the top border if the settings call for it
|
37
37
|
if settings.border.top?
|
38
|
-
canvas.stroke(stroke_left, stroke_top, top_border_stroke
|
38
|
+
canvas.stroke(stroke_left, stroke_top, top_border_stroke, formatting, &block)
|
39
39
|
stroke_top += 1
|
40
40
|
end
|
41
41
|
# Precalculate the middle border container grids with more than 1 row
|
42
|
-
middle_border = dimensions.num_rows > 1 ? middle_border_stroke
|
42
|
+
middle_border = dimensions.num_rows > 1 ? middle_border_stroke : ''
|
43
|
+
|
44
|
+
vert_scrollbar = settings.scrollbar.vert? ? ScrollbarHelper.vert(
|
45
|
+
dimensions.children_height + dimensions.padding_height,
|
46
|
+
dimensions.inner_grid_height,
|
47
|
+
canvas_coords.content_top - canvas_coords.offset_content_top,
|
48
|
+
) : []
|
43
49
|
|
44
50
|
# Paint each grid row by row
|
45
51
|
dimensions.num_rows.times do |row_num|
|
@@ -53,8 +59,9 @@ module WhirledPeas
|
|
53
59
|
|
54
60
|
# Paint the interior of each row (horizontal borders, veritical scroll bar and
|
55
61
|
# background color for the padding and content area)
|
56
|
-
|
57
|
-
|
62
|
+
dimensions.inner_grid_height.times do |row_within_cell|
|
63
|
+
content_line = content_line_stroke(row_within_cell, vert_scrollbar)
|
64
|
+
canvas.stroke(stroke_left, stroke_top, content_line, formatting, &block)
|
58
65
|
stroke_top += 1
|
59
66
|
end
|
60
67
|
|
@@ -67,7 +74,7 @@ module WhirledPeas
|
|
67
74
|
|
68
75
|
# Paint the bottom border if the settings call for it
|
69
76
|
if settings.border.bottom?
|
70
|
-
canvas.stroke(stroke_left, stroke_top, bottom_border_stroke
|
77
|
+
canvas.stroke(stroke_left, stroke_top, bottom_border_stroke, formatting, &block)
|
71
78
|
stroke_top += 1
|
72
79
|
end
|
73
80
|
end
|
@@ -177,55 +184,49 @@ module WhirledPeas
|
|
177
184
|
end
|
178
185
|
|
179
186
|
# Return the stroke for the top border
|
180
|
-
def top_border_stroke
|
187
|
+
def top_border_stroke
|
181
188
|
line_stroke(
|
182
189
|
settings.border.style.top_left,
|
183
190
|
settings.border.style.top_junc,
|
184
191
|
settings.border.style.top_right
|
185
192
|
) do
|
186
|
-
settings.border.style.top_horiz * (
|
193
|
+
settings.border.style.top_horiz * (dimensions.inner_grid_width + (settings.scrollbar.vert? ? 1 : 0))
|
187
194
|
end
|
188
195
|
end
|
189
196
|
|
190
197
|
# Return the stroke for an inner horizontal border
|
191
|
-
def middle_border_stroke
|
198
|
+
def middle_border_stroke
|
192
199
|
line_stroke(
|
193
200
|
settings.border.style.left_junc,
|
194
201
|
settings.border.style.cross_junc,
|
195
202
|
settings.border.style.right_junc
|
196
203
|
) do
|
197
|
-
settings.border.style.middle_horiz * (
|
204
|
+
settings.border.style.middle_horiz * (dimensions.inner_grid_width + (settings.scrollbar.vert? ? 1 : 0))
|
198
205
|
end
|
199
206
|
end
|
200
207
|
|
201
208
|
# Return the stroke for the bottom border
|
202
|
-
def bottom_border_stroke
|
209
|
+
def bottom_border_stroke
|
203
210
|
line_stroke(
|
204
211
|
settings.border.style.bottom_left,
|
205
212
|
settings.border.style.bottom_junc,
|
206
213
|
settings.border.style.bottom_right
|
207
214
|
) do
|
208
|
-
settings.border.style.bottom_horiz * (
|
215
|
+
settings.border.style.bottom_horiz * (dimensions.inner_grid_width + (settings.scrollbar.vert? ? 1 : 0))
|
209
216
|
end
|
210
217
|
end
|
211
218
|
|
212
219
|
# Return the stroke for a grid row between any borders
|
213
|
-
def content_line_stroke(
|
220
|
+
def content_line_stroke(row_within_cell, vert_scrollbar)
|
214
221
|
line_stroke(
|
215
222
|
settings.border.style.left_vert,
|
216
223
|
settings.border.style.middle_vert,
|
217
224
|
settings.border.style.right_vert,
|
218
225
|
) do
|
219
226
|
if settings.scrollbar.vert?
|
220
|
-
|
221
|
-
dimensions.children_height + dimensions.padding_height,
|
222
|
-
canvas_coords.inner_grid_height,
|
223
|
-
canvas_coords.top - canvas_coords.offset_content_top,
|
224
|
-
row_within_cell
|
225
|
-
)
|
226
|
-
PADDING * canvas_coords.inner_grid_width + scrollbar_char
|
227
|
+
PADDING * dimensions.inner_grid_width + vert_scrollbar[row_within_cell]
|
227
228
|
else
|
228
|
-
PADDING *
|
229
|
+
PADDING * dimensions.inner_grid_width
|
229
230
|
end
|
230
231
|
end
|
231
232
|
end
|
@@ -237,14 +238,11 @@ module WhirledPeas
|
|
237
238
|
settings.border.style.middle_vert,
|
238
239
|
settings.border.style.right_vert,
|
239
240
|
) do
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
col_within_cell
|
246
|
-
)
|
247
|
-
end.join
|
241
|
+
ScrollbarHelper.horiz(
|
242
|
+
dimensions.children_width + dimensions.padding_width,
|
243
|
+
dimensions.inner_grid_width,
|
244
|
+
canvas_coords.content_left - canvas_coords.offset_content_left
|
245
|
+
).join
|
248
246
|
end
|
249
247
|
end
|
250
248
|
end
|
@@ -15,6 +15,7 @@ module WhirledPeas
|
|
15
15
|
"#{indent}* #{painter.class}(#{painter.name})",
|
16
16
|
]
|
17
17
|
info << "#{indent + ' '}- Dimensions(#{dimensions})"
|
18
|
+
info << "#{indent + ' '}- Theme=#{painter.settings.theme.inspect}" if indent == ''
|
18
19
|
info << "#{indent + ' '}- Settings"
|
19
20
|
info << Settings::Debugger.new(painter.settings).debug(indent + ' ')
|
20
21
|
if painter.is_a?(TextPainter)
|
@@ -5,6 +5,10 @@ require_relative 'content_painter'
|
|
5
5
|
module WhirledPeas
|
6
6
|
module Graphics
|
7
7
|
class GraphPainter < ContentPainter
|
8
|
+
# The number of units along the Y-axis a single character can be divided into
|
9
|
+
Y_AXIS_SCALE = 2
|
10
|
+
private_constant :Y_AXIS_SCALE
|
11
|
+
|
8
12
|
def paint(canvas, left, top, &block)
|
9
13
|
axis_formatting = [*settings.axis_color, *settings.bg_color]
|
10
14
|
plot_formatting = [*settings.color, *settings.bg_color]
|
@@ -26,8 +30,8 @@ module WhirledPeas
|
|
26
30
|
min_y = 1.0 / 0
|
27
31
|
max_y = -1.0 / 0
|
28
32
|
if settings.width
|
29
|
-
interpolated = inner_width.times.map do |i|
|
30
|
-
x = (i * (content.length - 1).to_f / inner_width).floor
|
33
|
+
interpolated = (inner_width + 1).times.map do |i|
|
34
|
+
x = (i * (content.length - 1).to_f / (inner_width + 1)).floor
|
31
35
|
max_y = content[x] if content[x] > max_y
|
32
36
|
min_y = content[x] if content[x] < min_y
|
33
37
|
content[x]
|
@@ -39,31 +43,34 @@ module WhirledPeas
|
|
39
43
|
min_y = y if y < min_y
|
40
44
|
end
|
41
45
|
end
|
46
|
+
if min_y == max_y
|
47
|
+
min_y -= 1
|
48
|
+
max_y += 1
|
49
|
+
end
|
42
50
|
scaled = interpolated.map do |y|
|
43
|
-
|
51
|
+
inner_height * (y - min_y).to_f / (max_y - min_y)
|
44
52
|
end
|
53
|
+
|
45
54
|
@plot_lines = Array.new(inner_height) { '' }
|
46
|
-
scaled.each.with_index do |y, x_index|
|
55
|
+
scaled[0..-2].each.with_index do |y, x_index|
|
56
|
+
last = x_index == scaled.length - 2
|
57
|
+
|
58
|
+
prev_y = x_index == 0 ? y : scaled[x_index - 1]
|
59
|
+
next_y = scaled[x_index + 1]
|
60
|
+
|
61
|
+
min_y = [(prev_y + y) / 2, y, last ? next_y : (y + next_y) / 2].min
|
62
|
+
min_y = (Y_AXIS_SCALE * min_y).round.to_f / Y_AXIS_SCALE
|
63
|
+
|
64
|
+
max_y = [(prev_y + y) / 2, y, last ? next_y : (y + next_y) / 2].max
|
65
|
+
max_y = (Y_AXIS_SCALE * max_y).round.to_f / Y_AXIS_SCALE
|
66
|
+
|
47
67
|
@plot_lines.each.with_index do |row, row_index|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
y >= scaled[x_index - 1]
|
55
|
-
[true, y]
|
56
|
-
else
|
57
|
-
scaled[x_index + 1] >= y
|
58
|
-
[true, scaled[x_index + 1]]
|
59
|
-
end
|
60
|
-
if asc
|
61
|
-
top_half = y == top_half_index || (y...next_y).include?(top_half_index)
|
62
|
-
bottom_half = y == bottom_half_index || (y...next_y).include?(bottom_half_index)
|
63
|
-
else
|
64
|
-
top_half = y == top_half_index || (next_y...y).include?(top_half_index)
|
65
|
-
bottom_half = y == bottom_half_index || (next_y...y).include?(bottom_half_index)
|
66
|
-
end
|
68
|
+
bottom_value = inner_height - row_index - 1
|
69
|
+
top_value = bottom_value + 1.0 / Y_AXIS_SCALE
|
70
|
+
|
71
|
+
top_half = min_y == top_value || (min_y <= top_value && top_value < max_y)
|
72
|
+
bottom_half = min_y == bottom_value || (min_y <= bottom_value && bottom_value < max_y)
|
73
|
+
|
67
74
|
row << if top_half && bottom_half
|
68
75
|
'█'
|
69
76
|
elsif top_half
|
@@ -83,7 +90,7 @@ module WhirledPeas
|
|
83
90
|
end
|
84
91
|
|
85
92
|
def inner_width
|
86
|
-
settings.width.nil? ? content.length : settings.width - 1
|
93
|
+
(settings.width.nil? ? content.length : settings.width) - 1
|
87
94
|
end
|
88
95
|
|
89
96
|
def axes_lines
|
@@ -15,18 +15,18 @@ module WhirledPeas
|
|
15
15
|
private_constant :SCROLL_HANDLE_SCALE
|
16
16
|
|
17
17
|
class << self
|
18
|
-
#
|
18
|
+
# Return the characters to paint the horizontal scroll bar with for the given column
|
19
19
|
#
|
20
|
-
# @see #
|
21
|
-
def
|
22
|
-
|
20
|
+
# @see #scroll_chars for more details
|
21
|
+
def horiz(col_count, viewable_col_count, first_visible_col)
|
22
|
+
scroll_chars(col_count, viewable_col_count, first_visible_col, HORIZONTAL)
|
23
23
|
end
|
24
24
|
|
25
|
-
#
|
25
|
+
# Return the characters to paint the vertical scroll bar with for the given row
|
26
26
|
#
|
27
|
-
# @see #
|
28
|
-
def
|
29
|
-
|
27
|
+
# @see #scroll_chars for more details
|
28
|
+
def vert(row_count, viewable_row_count, first_visible_row)
|
29
|
+
scroll_chars(row_count, viewable_row_count, first_visible_row, VERTICAL)
|
30
30
|
end
|
31
31
|
|
32
32
|
private
|
@@ -37,15 +37,16 @@ module WhirledPeas
|
|
37
37
|
# @param viewable_count [Integer] number of rows/columns visible in the viewport
|
38
38
|
# @param first_visible [Integer] zero-based index of the first row/column that is visible
|
39
39
|
# in the viewport
|
40
|
-
# @param
|
41
|
-
#
|
42
|
-
#
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
return
|
48
|
-
return
|
40
|
+
# @param chars [Array<String>] an array with four 1-character strings, the frist is the
|
41
|
+
# gutter (i.e. no scrolbar handle visible), then the "second half" scrollbar character,
|
42
|
+
# then second is the "first half" scrollbar character, and finally the "full"
|
43
|
+
def scroll_chars(total_count, viewable_count, first_visible, chars)
|
44
|
+
# Start by initializing the scroll back to to all gutters
|
45
|
+
scrollbar = Array.new(viewable_count) { chars[0] }
|
46
|
+
|
47
|
+
return scrollbar if total_count == 0
|
48
|
+
return scrollbar if viewable_count == 0
|
49
|
+
return scrollbar if viewable_count >= total_count
|
49
50
|
|
50
51
|
# The scroll handle has the exact same relative size and position in the scroll gutter
|
51
52
|
# that the viewable content has in the total content area. For example, a content area
|
@@ -92,31 +93,32 @@ module WhirledPeas
|
|
92
93
|
# Always use the same length for the scrollbar so it does not give an inchworm effect
|
93
94
|
# as it scrolls along. This will calculate the "ideal" length of the scroll bar if we
|
94
95
|
# could infinitely divide a character.
|
95
|
-
|
96
|
+
length = (viewable_count ** 2).to_f / total_count
|
96
97
|
|
97
98
|
# Round the length to the nearst "scaled" value
|
98
|
-
|
99
|
+
length = (SCROLL_HANDLE_SCALE * length).round.to_f / SCROLL_HANDLE_SCALE
|
99
100
|
|
100
101
|
# Ensure we have a scrollbar!
|
101
|
-
|
102
|
+
length = 1.0 / SCROLL_HANDLE_SCALE if length == 0
|
102
103
|
|
103
104
|
# Find the "ideal" position of where the scrollbar should start.
|
104
|
-
|
105
|
+
start = first_visible * viewable_count.to_f / total_count
|
105
106
|
|
106
107
|
# Round the start to the nearest "scaled" value
|
107
|
-
|
108
|
+
start = (SCROLL_HANDLE_SCALE * start).round.to_f / SCROLL_HANDLE_SCALE
|
108
109
|
|
109
110
|
# Make sure we didn't scroll off the page!
|
110
|
-
|
111
|
+
start -= length if start == viewable_count
|
111
112
|
|
112
|
-
|
113
|
-
|
114
|
-
curr_1 = curr + 1.0 / SCROLL_HANDLE_SCALE
|
113
|
+
(start.floor..[(start + length).floor, viewable_count - 1].min).each do |curr_0|
|
114
|
+
curr_1 = curr_0 + 1.0 / SCROLL_HANDLE_SCALE
|
115
115
|
|
116
|
-
|
117
|
-
|
116
|
+
first_half = start <= curr_0 && curr_0 < start + length ? 2 : 0
|
117
|
+
second_half = start <= curr_1 && curr_1 < start + length ? 1 : 0
|
118
118
|
|
119
|
-
|
119
|
+
scrollbar[curr_0] = chars[second_half | first_half]
|
120
|
+
end
|
121
|
+
scrollbar
|
120
122
|
end
|
121
123
|
end
|
122
124
|
end
|