Add nav DSL to TUI::Page; helpers accumulates across calls
Page#nav sets up up/down key handlers for four common patterns: nav :menu, size: – wrapping @menu_sel selection nav :cycle – wrapping @item_sel over @items nav :list, window: – @item_sel/@scroll with a visible window nav :scroll, content:, window: – @scroll over arbitrary content size/window accept an integer or a lambda evaluated on the Context at runtime, so terminal-size-dependent values work naturally. TUI#helpers now accumulates into one module instead of replacing it, so configure methods on page classes can each extend helpers without clobbering previous calls. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -11,8 +11,9 @@ module BBS
|
||||
end
|
||||
|
||||
def initialize
|
||||
@pages = {}
|
||||
@start_page = :idle
|
||||
@pages = {}
|
||||
@start_page = :idle
|
||||
@helper_module = Module.new
|
||||
end
|
||||
|
||||
def init(&block) = @init_block = block
|
||||
@@ -20,7 +21,7 @@ module BBS
|
||||
def start(name) = @start_page = name
|
||||
|
||||
def helpers(&block)
|
||||
@helper_module = Module.new(&block)
|
||||
@helper_module.module_eval(&block)
|
||||
end
|
||||
|
||||
def page(name, &block)
|
||||
@@ -41,6 +42,44 @@ module BBS
|
||||
def render(&block) = @render_block = block
|
||||
def key(k, &block) = (@key_bindings[k] = block)
|
||||
def printable(&block) = (@key_bindings[:printable] = block)
|
||||
|
||||
def nav(mode, **opts)
|
||||
lift = ->(v) { v.is_a?(Proc) ? v : -> { v } }
|
||||
|
||||
case mode
|
||||
when :menu
|
||||
size = lift.(opts.fetch(:size))
|
||||
key(:up) { @menu_sel = (@menu_sel - 1) % instance_exec(&size) }
|
||||
key(:down) { @menu_sel = (@menu_sel + 1) % instance_exec(&size) }
|
||||
|
||||
when :cycle
|
||||
key(:up) { @item_sel = (@item_sel - 1) % @items.size if @items.any? }
|
||||
key(:down) { @item_sel = (@item_sel + 1) % @items.size if @items.any? }
|
||||
|
||||
when :list
|
||||
window = lift.(opts.fetch(:window))
|
||||
key(:up) do
|
||||
return if @item_sel <= 0
|
||||
@item_sel -= 1
|
||||
@scroll = @item_sel if @item_sel < @scroll
|
||||
end
|
||||
key(:down) do
|
||||
return if @item_sel >= @items.size - 1
|
||||
@item_sel += 1
|
||||
wh = instance_exec(&window)
|
||||
@scroll = @item_sel - wh + 1 if @item_sel >= @scroll + wh
|
||||
end
|
||||
|
||||
when :scroll
|
||||
content = opts.fetch(:content)
|
||||
window = lift.(opts.fetch(:window))
|
||||
key(:up) { @scroll = [@scroll - 1, 0].max }
|
||||
key(:down) do
|
||||
max = [instance_exec(&content).size - instance_exec(&window), 0].max
|
||||
@scroll = [@scroll + 1, max].min
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user