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:
@@ -1,6 +1,6 @@
|
|||||||
Gem::Specification.new do |s|
|
Gem::Specification.new do |s|
|
||||||
s.name = 'bbs'
|
s.name = 'bbs'
|
||||||
s.version = '0.2.0'
|
s.version = '0.3.0'
|
||||||
s.summary = 'Universal telnet BBS server library'
|
s.summary = 'Universal telnet BBS server library'
|
||||||
s.author = 'Zsolt Tasnadi'
|
s.author = 'Zsolt Tasnadi'
|
||||||
s.files = Dir['lib/**/*.rb']
|
s.files = Dir['lib/**/*.rb']
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ module BBS
|
|||||||
def initialize
|
def initialize
|
||||||
@pages = {}
|
@pages = {}
|
||||||
@start_page = :idle
|
@start_page = :idle
|
||||||
|
@helper_module = Module.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def init(&block) = @init_block = block
|
def init(&block) = @init_block = block
|
||||||
@@ -20,7 +21,7 @@ module BBS
|
|||||||
def start(name) = @start_page = name
|
def start(name) = @start_page = name
|
||||||
|
|
||||||
def helpers(&block)
|
def helpers(&block)
|
||||||
@helper_module = Module.new(&block)
|
@helper_module.module_eval(&block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def page(name, &block)
|
def page(name, &block)
|
||||||
@@ -41,6 +42,44 @@ module BBS
|
|||||||
def render(&block) = @render_block = block
|
def render(&block) = @render_block = block
|
||||||
def key(k, &block) = (@key_bindings[k] = block)
|
def key(k, &block) = (@key_bindings[k] = block)
|
||||||
def printable(&block) = (@key_bindings[:printable] = 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
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user