whirled_peas 0.11.0 → 0.11.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 +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
|