whirled_peas 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/README.md +88 -24
  4. data/examples/components.rb +35 -0
  5. data/examples/scrolling.rb +8 -19
  6. data/lib/whirled_peas.rb +30 -16
  7. data/lib/whirled_peas/command/config_command.rb +3 -2
  8. data/lib/whirled_peas/command/play.rb +3 -2
  9. data/lib/whirled_peas/command/themes.rb +3 -2
  10. data/lib/whirled_peas/component.rb +35 -0
  11. data/lib/whirled_peas/component/list_with_active.rb +88 -0
  12. data/lib/whirled_peas/graphics/box_painter.rb +4 -4
  13. data/lib/whirled_peas/graphics/composer.rb +4 -0
  14. data/lib/whirled_peas/graphics/container_coords.rb +24 -2
  15. data/lib/whirled_peas/graphics/container_painter.rb +9 -119
  16. data/lib/whirled_peas/graphics/debugger.rb +1 -7
  17. data/lib/whirled_peas/graphics/scrollbar_helper.rb +124 -0
  18. data/lib/whirled_peas/null_logger.rb +0 -1
  19. data/lib/whirled_peas/settings/container_settings.rb +12 -5
  20. data/lib/whirled_peas/settings/debugger.rb +1 -1
  21. data/lib/whirled_peas/settings/position.rb +17 -5
  22. data/lib/whirled_peas/version.rb +1 -1
  23. data/screen_test/components/list_with_active/l2r_active_color.frame +1 -0
  24. data/screen_test/components/list_with_active/l2r_active_color.rb +18 -0
  25. data/screen_test/components/list_with_active/l2r_position_end.frame +1 -0
  26. data/screen_test/components/list_with_active/l2r_position_end.rb +16 -0
  27. data/screen_test/components/list_with_active/l2r_position_middle.frame +1 -0
  28. data/screen_test/components/list_with_active/l2r_position_middle.rb +16 -0
  29. data/screen_test/components/list_with_active/l2r_position_start.frame +1 -0
  30. data/screen_test/components/list_with_active/l2r_position_start.rb +16 -0
  31. data/screen_test/components/list_with_active/l2r_separator.frame +1 -0
  32. data/screen_test/components/list_with_active/l2r_separator.rb +17 -0
  33. data/screen_test/components/list_with_active/t2b_active_color.frame +1 -0
  34. data/screen_test/components/list_with_active/t2b_active_color.rb +19 -0
  35. data/screen_test/components/list_with_active/t2b_position_end.frame +1 -0
  36. data/screen_test/components/list_with_active/t2b_position_end.rb +17 -0
  37. data/screen_test/components/list_with_active/t2b_position_middle.frame +1 -0
  38. data/screen_test/components/list_with_active/t2b_position_middle.rb +17 -0
  39. data/screen_test/components/list_with_active/t2b_position_start.frame +1 -0
  40. data/screen_test/components/list_with_active/t2b_position_start.rb +17 -0
  41. data/screen_test/components/list_with_active/t2b_separator.frame +1 -0
  42. data/screen_test/components/list_with_active/t2b_separator.rb +18 -0
  43. data/screen_test/elements/theme.rb +1 -1
  44. data/screen_test/settings/{position/box_top_negative.frame → content_start/box_bottom.frame} +0 -0
  45. data/screen_test/settings/content_start/box_bottom.rb +17 -0
  46. data/screen_test/settings/{position → content_start}/box_left.frame +0 -0
  47. data/screen_test/settings/{position/box_top.rb → content_start/box_left.rb} +1 -1
  48. data/screen_test/settings/{position → content_start}/box_left_negative.frame +0 -0
  49. data/screen_test/settings/{position → content_start}/box_left_negative.rb +1 -1
  50. data/screen_test/settings/content_start/box_right.frame +1 -0
  51. data/screen_test/settings/content_start/box_right.rb +17 -0
  52. data/screen_test/settings/{position → content_start}/box_top.frame +0 -0
  53. data/screen_test/settings/{position/box_left.rb → content_start/box_top.rb} +1 -1
  54. data/screen_test/settings/content_start/box_top_negative.frame +1 -0
  55. data/screen_test/settings/{position → content_start}/box_top_negative.rb +1 -1
  56. data/screen_test/settings/{position → content_start}/grid_left.frame +0 -0
  57. data/screen_test/settings/{position → content_start}/grid_left.rb +1 -1
  58. data/screen_test/settings/{position → content_start}/grid_left_negative.frame +0 -0
  59. data/screen_test/settings/{position → content_start}/grid_left_negative.rb +1 -1
  60. data/screen_test/settings/{position → content_start}/grid_top.frame +0 -0
  61. data/screen_test/settings/{position → content_start}/grid_top.rb +1 -1
  62. data/screen_test/settings/{position → content_start}/grid_top_negative.frame +0 -0
  63. data/screen_test/settings/{position → content_start}/grid_top_negative.rb +1 -1
  64. data/screen_test/settings/scroll/horiz_box.frame +1 -1
  65. data/screen_test/settings/scroll/horiz_box.rb +2 -4
  66. data/screen_test/settings/scroll/horiz_box_align_center.rb +2 -4
  67. data/screen_test/settings/scroll/horiz_box_align_right.rb +2 -4
  68. data/screen_test/settings/scroll/vert_box.frame +1 -1
  69. data/screen_test/settings/scroll/vert_box.rb +5 -7
  70. metadata +46 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7c1c4b2f603c535f98d7578741059e0d949ccff4e315fc88c36c13fc2fa58de5
4
- data.tar.gz: a9c92f62d2dcb7c7c1983bf6e6e8fa66bb5a92abcec0ae689ca4efc342083625
3
+ metadata.gz: 7f73ce3a27741b9c790785fe5aad7179c6db66e045ca1c2e43af33887c1fd4d9
4
+ data.tar.gz: bd19233e2d81a2d4e985bc4c8b0ec3ec07b8fe4691f0c70c5a2374add780bc9b
5
5
  SHA512:
6
- metadata.gz: 8e746107b95a5176d89792606a76935c84c3686452b2abf99c5383df676263684a096130c18cf07080fbc9ede4dc61b9ae220efe4fd8313e933c230e73d8b1b0
7
- data.tar.gz: d5dca0db34f358072134a94ae8b5765abd60d45f18de7496dc0c410cd665c2e9ef91ef33989d00317caef1fd472c210e892af13d8a65bc3126ea37b201dc1b43
6
+ metadata.gz: 9c2a41a72c30eb2c96161c23bb4f47a37dd9052ca1206cdec2d714d3266b0a6e3eb58bc8dab0dea0517eaf1fe7c5743323a8a7579319e81fdce80b9d65992504
7
+ data.tar.gz: 1b120aa9b5327880dcdcffbb37cfb77b63a06be55089f77efe7c4da104ce36e65893412178b5efcc31d6f7a3b9aed8353bbe076ea0131f52a142910d251bc61f
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.11.0 - 2021-01-30
4
+
5
+ - [c1f3d94](https://github.com/tcollier/whirled_peas/tree/c1f3d944a35305c3032681db13ffd6142a7e19e4): Add component support
6
+
3
7
  ## v0.10.0 - 2021-01-29
4
8
 
5
9
  - [3063a2b](https://github.com/tcollier/whirled_peas/tree/3063a2becb7680b5e320a1733b3da933e6c65210): Add built-in and user-defined themes
data/README.md CHANGED
@@ -245,30 +245,86 @@ template.add_box do
245
245
  end
246
246
  ```
247
247
 
248
+ #### Components
249
+
250
+ A component is a composition of the core building blocks. This gem includes a handful of components and third parties can also add components using `WhirledPeas.register_component(name, component_class)` (the convention for `name` is a snake cased symbol). A component class must be constructed with no arguments, though can supply basic setters to allow for customizations. A component must also implement `#compose(composer, settings)`, which should attach elements to the composer. Thus a template can integrate with the component like
251
+
252
+ ```ruby
253
+ WhirledPeas.template do |composer, settings|
254
+ # Attach the component registered with the name `:my_component` to the template
255
+ WhirledPeas.component(composer, settings, :my_component) do |component|
256
+ # Configure the component
257
+ end
258
+ end
259
+ ```
260
+
261
+ ##### `:list_with_active`
262
+
263
+ This component presents a list of content (either horizontally of vertically) and places the item specified by `active_index` in the preferred position.
264
+
265
+ ```
266
+ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
267
+ ┃ green, blue, *indigo*, viole┃
268
+ ┃ ▗▄▄▄▄▄▄▄▄▄▄▄▄▄▄▖ ┃
269
+ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
270
+ ```
271
+
272
+ Note: in the diagram above, the item specified by the active index is highlighted with `*`s, these are for illustration onlhy. The component can highlight the item with a color and/or background color, but will _not_ add the `*`s.
273
+
274
+ This component takes the following options
275
+
276
+ **Required**
277
+
278
+ - `active_index` - the index of the active item
279
+ - `items` - the array of items to be displayed in the box
280
+
281
+ **Optional**
282
+
283
+ - `active_bg_color` - background color of the active item
284
+ - `active_color` - text color of the active item
285
+ - `flow` - `:l2r` or `:t2b`
286
+ - `separator` - string used to separate items in the list, e.g. `", "` for a horizontal list or `"----"` for a vertical list
287
+ - `viewport_size` - number of characters of the viewport in the flow direction
288
+
289
+ **Example**
290
+
291
+ ```ruby
292
+ WhirledPeas.template do |composer, settings|
293
+ WhirledPeas.component(composer, settings, :list_with_active) do |component|
294
+ component.items = %w[red orange yellow green blue indigo violet]
295
+ component.separator = ', '
296
+ component.active_index = active
297
+ component.viewport_size = 27
298
+ component.active_color = :blue
299
+ component.active_bg_color = :bright_yellow
300
+ end
301
+ end
302
+ ```
303
+
248
304
  #### Settings
249
305
 
250
306
  Each element type has an associated settings type, which provide a custom set of options to format the output. Child settings will inherit from the parent, where applicable. The table below lists all settings along with which element types the settings can be applied to (`Grid` and `Box` are containers)
251
307
 
252
- | Setting | Description | Default | Availability | Inherited |
253
- | ------------ | -------------------------------------------------------------------------------- | ---------- | ------------ | -------------------- |
254
- | `align` | Justifies the content in the horizontal direction | `:left` | containers | No |
255
- | `axis_color` | Color used to paint the axes of the graph (see [Colors](#colors)) | | `Graph` | No |
256
- | `bg_color` | Background color (see [Colors](#colors)) | | all | Yes |
257
- | `bold` | `true` makes the font bold | `false` | all | Yes |
258
- | `border` | Set the border for the lements | none | containers, | Only style and color |
259
- | `color` | Foreground text color (see [Colors](#colors)) | | all | Yes |
260
- | `flow` | Flow to display child elements (see [Display Flow](#display-flow)) | `:l2r` | containers | No |
261
- | `height` | Override the calculated height of an element's content area | | all | No |
262
- | `margin` | Set the (left, top, right, bottom) margin of the element | `0` | containers | No |
263
- | `num_cols` | Number of columns in the grid (must be set!) | | `Grid` | No |
264
- | `padding` | Set the (left, top, right, bottom) padding of the element | `0` | containers | No |
265
- | `position` | Set the (left, top) position of the element relative to parent content area | `0` | containers | No |
266
- | `scrollbar` | Display a scroll bar for vertical or horizontal scrolling | | `Box` | No |
267
- | `sizing` | Sizing model (`:content` or `:border`) used in conjunction with `width`/`height` | `:content` | `Box` | No |
268
- | `title_font` | Font used for "large" text (see [Large Text](#large-text), ignores `underline`) | | `Text` | No |
269
- | `underline` | `true` underlines the font | `false` | all | Yes |
270
- | `width` | Override the calculated width of an element's content area | | all | No |
271
- | `valign` | Justifies the content in the vertical direction | `:top` | containers | No |
308
+ | Setting | Description | Default | Availability | Inherited |
309
+ | --------------- | -------------------------------------------------------------------------------- | ---------- | ------------ | -------------------- |
310
+ | `align` | Justifies the content in the horizontal direction | `:left` | containers | No |
311
+ | `axis_color` | Color used to paint the axes of the graph (see [Colors](#colors)) | | `Graph` | No |
312
+ | `bg_color` | Background color (see [Colors](#colors)) | | all | Yes |
313
+ | `bold` | `true` makes the font bold | `false` | all | Yes |
314
+ | `border` | Set the border for the lements | none | containers, | Only style and color |
315
+ | `color` | Foreground text color (see [Colors](#colors)) | | all | Yes |
316
+ | `flow` | Flow to display child elements (see [Display Flow](#display-flow)) | `:l2r` | containers | No |
317
+ | `height` | Override the calculated height of an element's content area | | all | No |
318
+ | `margin` | Set the (left, top, right, bottom) margin of the element | `0` | containers | No |
319
+ | `num_cols` | Number of columns in the grid (must be set!) | | `Grid` | No |
320
+ | `padding` | Set the (left, top, right, bottom) padding of the element | `0` | containers | No |
321
+ | `content_start` | Set the (left, top, right, bottom) position of children | `0` | containers | No |
322
+ | `scrollbar` | Display a scroll bar for vertical or horizontal scrolling | | `Box` | No |
323
+ | `sizing` | Sizing model (`:content` or `:border`) used in conjunction with `width`/`height` | `:content` | `Box` | No |
324
+ | `title_font` | Font used for "large" text (see [Large Text](#large-text), ignores `underline`) | | `Text` | No |
325
+ | `underline` | `true` underlines the font | `false` | all | Yes |
326
+ | `width` | Override the calculated width of an element's content area | | all | No |
327
+ | `valign` | Justifies the content in the vertical direction | `:top` | containers | No |
272
328
 
273
329
  ##### Themes
274
330
 
@@ -276,7 +332,7 @@ The template builder (`WhirledPeas.template`) takes an optional `theme` argument
276
332
  You can define your own theme
277
333
 
278
334
  ```ruby
279
- WhirledPeas.define_theme(:my_theme) do |theme|
335
+ WhirledPeas.register_theme(:my_theme) do |theme|
280
336
  theme.bg_color = :bright_white
281
337
  theme.color = :blue
282
338
  theme.border_color = :bright_green
@@ -473,11 +529,19 @@ The `valign` setting takes one of several values
473
529
  ┗━━━━━━━━━┛
474
530
  ```
475
531
 
476
- ##### Position
532
+ ##### Content Start
533
+
534
+ Content start settings dictate the relative position from the content area where the children will get painted. Positive values for `left`/`top` result in moving the children leftward/downward, negative values shift children rightward/upward. Setting `right` or `bototm` will result in the end of the children to be painted relative to the right/bottom of the content area.
535
+
536
+ To set these values, use
477
537
 
478
- Position settings dictate the relative position from where the painter would have preferred to place the container. Negative numbers move the container left/up and positive numbers move it right/down. To set these values, use
538
+ - `set_content_start(left:, top:, right:, bottom:)`
539
+ - `content_start.left=`
540
+ - `content_start.top=`
541
+ - `content_start.right=`
542
+ - `content_start.bottom=`
479
543
 
480
- - `set_position(left:, top:)`
544
+ Note: setting `left` and `right` or `top` and `bottom` is not supported
481
545
 
482
546
  ##### Sizing Model
483
547
 
@@ -0,0 +1,35 @@
1
+ require 'bundler/setup'
2
+ require 'whirled_peas'
3
+ require 'whirled_peas/component/list_with_active'
4
+
5
+ class TemplateFactory
6
+ ITEMS = 400.times.map(&:itself)
7
+
8
+ def build(name, args)
9
+ active = args[:active]
10
+ WhirledPeas.template do |composer, settings|
11
+ WhirledPeas.component(composer, settings, :list_with_active) do |component, settings|
12
+ component.items = %w[red orange yellow green blue indigo violet]
13
+ component.separator = ', '
14
+ component.active_index = active
15
+ component.viewport_size = 27
16
+ component.active_color = :green
17
+ component.active_bg_color = :yellow
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ class Application
24
+ def start(producer)
25
+ producer.frameset(5, easing: :parametric) do |fs|
26
+ ITEMS.length.times { |i| fs.add_frame('intro', args: { active: i }) }
27
+ end
28
+ producer.add_frame('hold', duration: 1, args: { active: ITEMS.length - 1 })
29
+ end
30
+ end
31
+
32
+ WhirledPeas.configure do |config|
33
+ config.template_factory = TemplateFactory.new
34
+ config.application = Application.new
35
+ end
@@ -2,38 +2,27 @@ require 'bundler/setup'
2
2
  require 'whirled_peas'
3
3
 
4
4
  class TemplateFactory
5
- HPADDING = 0
6
- VPADDING = 0
7
5
  ITEM_COUNT = 64
8
6
 
9
7
  def build(name, args)
10
8
  top = args[:top]
11
9
  WhirledPeas.template do |composer, settings|
12
- settings.color = :green
13
10
  composer.add_box('Vert') do |composer, settings|
14
- settings.bg_color = :bright_red
15
- settings.full_border(color: :blue)
11
+ settings.full_border
16
12
  settings.set_scrollbar(vert: true)
17
13
  settings.height = 12
18
- composer.add_box('Inner') do |composer, settings|
19
- settings.flow = :t2b
20
- settings.set_padding(left: HPADDING, right: HPADDING, top: VPADDING, bottom: VPADDING)
21
- settings.set_position(top: top)
22
- ITEM_COUNT.times do |i|
23
- composer.add_text { "%2d" % i }
24
- end
14
+ settings.flow = :t2b
15
+ settings.content_start.top = top
16
+ ITEM_COUNT.times do |i|
17
+ composer.add_text { "%2d" % i }
25
18
  end
26
19
  end
27
20
  composer.add_box('Horiz') do |composer, settings|
28
- settings.bg_color = :bright_red
29
- settings.full_border(color: :blue)
30
- settings.set_padding(left: HPADDING, right: HPADDING, top: VPADDING, bottom: VPADDING)
21
+ settings.full_border
31
22
  settings.set_scrollbar(horiz: true)
32
23
  settings.width = 12
33
- composer.add_box('Inner') do |composer, settings|
34
- settings.set_position(left: top)
35
- ITEM_COUNT.times.map { |i| (i % 10).to_s }.join
36
- end
24
+ settings.content_start.left = top
25
+ ITEM_COUNT.times.map { |i| (i % 10).to_s }.join
37
26
  end
38
27
  end
39
28
  end
@@ -7,24 +7,38 @@ require 'whirled_peas/utils'
7
7
  require 'whirled_peas/version'
8
8
 
9
9
  module WhirledPeas
10
- def self.config
11
- @config ||= Config.new
12
- end
10
+ class << self
11
+ def configure(&block)
12
+ yield config
13
+ end
13
14
 
14
- def self.configure(&block)
15
- yield config
16
- end
15
+ def register_component(name, klass)
16
+ require 'whirled_peas/component'
17
+ Component::Factory.register(name, klass)
18
+ end
17
19
 
18
- def self.template(theme_name=nil, &block)
19
- require 'whirled_peas/graphics/composer'
20
- Graphics::Composer.build(theme_name, &block)
21
- end
20
+ def component(composer, settings, name, &block)
21
+ require 'whirled_peas/component'
22
+ component = Component::Factory.build(name)
23
+ yield component
24
+ component.compose(composer, settings)
25
+ end
26
+
27
+ def template(theme_name=nil, &block)
28
+ require 'whirled_peas/graphics/composer'
29
+ Graphics::Composer.build(theme_name, &block)
30
+ end
31
+
32
+ def register_theme(name, &block)
33
+ require 'whirled_peas/settings/theme'
34
+ require 'whirled_peas/settings/theme_library'
35
+ theme = Settings::Theme.new
36
+ yield theme
37
+ Settings::ThemeLibrary.add(name, theme)
38
+ end
22
39
 
23
- def self.define_theme(name, &block)
24
- require 'whirled_peas/settings/theme'
25
- require 'whirled_peas/settings/theme_library'
26
- theme = Settings::Theme.new
27
- yield theme
28
- Settings::ThemeLibrary.add(name, theme)
40
+ def config
41
+ @config ||= Config.new
42
+ end
29
43
  end
30
44
  end
@@ -8,8 +8,9 @@ module WhirledPeas
8
8
  class ConfigCommand < Base
9
9
  def start
10
10
  require config_file
11
- rescue LoadError
12
- puts "Error loading #{config_file}"
11
+ rescue LoadError => e
12
+ puts e
13
+ puts e.backtrace.join("\n")
13
14
  exit(1)
14
15
  end
15
16
 
@@ -38,8 +38,9 @@ module WhirledPeas
38
38
  config.application.start(producer)
39
39
  end
40
40
  end
41
- rescue LoadError
42
- puts "Error loading #{config_file}"
41
+ rescue LoadError => e
42
+ puts e
43
+ puts e.backtrace.join("\n")
43
44
  exit(1)
44
45
  end
45
46
 
@@ -49,8 +49,9 @@ module WhirledPeas
49
49
  break if gets.chomp == 'q'
50
50
  end
51
51
  end
52
- rescue LoadError
53
- puts "Error loading #{config_file}"
52
+ rescue LoadError => e
53
+ puts e
54
+ puts e.backtrace.join("\n")
54
55
  exit(1)
55
56
  end
56
57
 
@@ -0,0 +1,35 @@
1
+ module WhirledPeas
2
+ module Component
3
+ module Factory
4
+ class << self
5
+ def register(name, klass)
6
+ classes[name] = klass
7
+ end
8
+
9
+ def build(name)
10
+ unless classes.key?(name)
11
+ expected = classes.keys.join(', ')
12
+ raise ArgumentError, "Unrecognized component: #{name.inspect}, expecting one of #{expected}"
13
+ end
14
+ @classes[name].new
15
+ end
16
+
17
+ private
18
+
19
+ def classes
20
+ return @classes if @classes
21
+ @classes = {}
22
+ Component.constants.each do |const|
23
+ next if const == name
24
+ klass = Component.const_get(const)
25
+ next unless klass.is_a?(Class)
26
+ name = const.to_s.gsub(/([a-z])([A-Z])/, '\1_\2').downcase.to_sym
27
+ @classes[name] = klass
28
+ end
29
+ @classes
30
+ end
31
+ end
32
+ end
33
+ end
34
+ private_constant :Component
35
+ end
@@ -0,0 +1,88 @@
1
+ module WhirledPeas
2
+ module Component
3
+ class ListWithActive
4
+ attr_accessor :active_index, :active_color, :active_bg_color, :separator
5
+
6
+ attr_reader :items
7
+
8
+ attr_writer :flow, :viewport_size
9
+
10
+ def items=(value)
11
+ @items = value.map(&:to_s)
12
+ end
13
+
14
+ def flow
15
+ @flow || :l2r
16
+ end
17
+
18
+ def total_size
19
+ @total_size ||= if flow == :l2r
20
+ size = separator.nil? ? 0 : (items.count - 1) * separator.length
21
+ items.each { |item| size += item.length }
22
+ size
23
+ else
24
+ items.count + (separator.nil? ? 0 : items.count - 1)
25
+ end
26
+ end
27
+
28
+ def viewport_size
29
+ @viewport_size || total_size
30
+ end
31
+
32
+ def compose(composer, settings)
33
+ %i[items active_index].each do |required_attr|
34
+ if send(required_attr).nil?
35
+ raise ArugmentError, "Require field #{required_attr} missing"
36
+ end
37
+ end
38
+
39
+ composer.add_box('ListWithActive') do |composer, settings|
40
+ settings.flow = flow
41
+ settings.align = :left
42
+ settings.full_border
43
+ if flow == :l2r
44
+ settings.width = viewport_size
45
+ active_start = separator.nil? ? 0 : active_index * separator.length
46
+ items.first(active_index).each do |item|
47
+ active_start += item.length
48
+ end
49
+ active_size = items[active_index].length
50
+ else
51
+ settings.height = viewport_size
52
+ active_start = active_index + (separator.nil? ? 0 : active_index)
53
+ active_size = 1
54
+ end
55
+
56
+ if viewport_size < total_size
57
+ front_padding = (viewport_size - active_size) * 0.667
58
+ offset = (active_start - front_padding).round
59
+ if offset < 0
60
+ offset = 0
61
+ elsif offset > total_size - viewport_size
62
+ offset = total_size - viewport_size
63
+ end
64
+
65
+ if flow == :l2r
66
+ settings.content_start.left = -offset
67
+ settings.scrollbar.horiz = true
68
+ else
69
+ settings.content_start.top = -offset
70
+ settings.scrollbar.vert = true
71
+ end
72
+ end
73
+
74
+ items.each.with_index do |item, index|
75
+ composer.add_text { separator } if !separator.nil? && index > 0
76
+ composer.add_text do |_, settings|
77
+ if index == active_index
78
+ settings.bg_color = active_bg_color
79
+ settings.color = active_color
80
+ end
81
+ item
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end