new windows types
This commit is contained in:
98
lib/bbs/windows/button_bar.rb
Normal file
98
lib/bbs/windows/button_bar.rb
Normal file
@@ -0,0 +1,98 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../widgets'
|
||||
|
||||
module BBS
|
||||
module Windows
|
||||
# Lays out a row of buttons at the bottom of a window.
|
||||
#
|
||||
# Button descriptor:
|
||||
# { key:, label:, on_click:, primary:, cancel:, align:, keep_open: }
|
||||
#
|
||||
# `on_click` receives the BBS::Window as its only argument and may return
|
||||
# :keep to keep the window open. Any other return value (or nil) causes
|
||||
# the window to be closed after the handler.
|
||||
#
|
||||
# `primary: true` gets initial focus on the button.
|
||||
# `cancel: true` is informational only — ESC closes the window through the
|
||||
# standard Window#close_key path. If you also want a cancel-specific side
|
||||
# effect on ESC, set `window.on_close = ...` manually.
|
||||
# `align: :left | :right | :center` — default is :center for a single
|
||||
# button, :right otherwise. Left-aligned buttons stack from the left edge;
|
||||
# right-aligned buttons stack flush against the right edge in declaration
|
||||
# order (so the last right-aligned button sits closest to the edge).
|
||||
module ButtonBar
|
||||
module_function
|
||||
|
||||
# Returns { widgets:, primary:, by_key: }.
|
||||
def attach(window, app, descriptors)
|
||||
return { widgets: [], primary: nil, by_key: {} } if descriptors.nil? || descriptors.empty?
|
||||
|
||||
widgets = descriptors.map do |d|
|
||||
BBS::Widgets::Button.new(label: d[:label], on_click: build_handler(window, app, d))
|
||||
end
|
||||
|
||||
default_align = descriptors.length == 1 ? :center : :right
|
||||
aligns = descriptors.map { |d| d[:align] || default_align }
|
||||
|
||||
row_y = window.bounds.y + window.bounds.height - 2
|
||||
left_x0 = window.bounds.x + 2
|
||||
right_x1 = window.bounds.x + window.bounds.width - 2
|
||||
win_x0 = window.bounds.x
|
||||
win_w = window.bounds.width
|
||||
|
||||
x = left_x0
|
||||
widgets.each_with_index do |w, i|
|
||||
next unless aligns[i] == :left
|
||||
bw = button_width(w)
|
||||
w.layout(x, row_y, bw, 1)
|
||||
x += bw + 1
|
||||
end
|
||||
|
||||
right_indices = aligns.each_index.select { |i| aligns[i] == :right }
|
||||
total_right = right_indices.sum { |i| button_width(widgets[i]) + 1 } - 1
|
||||
total_right = [total_right, 0].max
|
||||
x = right_x1 - total_right + 1
|
||||
right_indices.each do |i|
|
||||
bw = button_width(widgets[i])
|
||||
widgets[i].layout(x, row_y, bw, 1)
|
||||
x += bw + 1
|
||||
end
|
||||
|
||||
center_indices = aligns.each_index.select { |i| aligns[i] == :center }
|
||||
total_center = center_indices.sum { |i| button_width(widgets[i]) + 1 } - 1
|
||||
total_center = [total_center, 0].max
|
||||
x = win_x0 + (win_w - total_center) / 2
|
||||
center_indices.each do |i|
|
||||
bw = button_width(widgets[i])
|
||||
widgets[i].layout(x, row_y, bw, 1)
|
||||
x += bw + 1
|
||||
end
|
||||
|
||||
widgets.each { |w| window.add(w) }
|
||||
|
||||
primary_idx = descriptors.index { |d| d[:primary] }
|
||||
primary = primary_idx ? widgets[primary_idx] : nil
|
||||
|
||||
by_key = {}
|
||||
descriptors.each_with_index { |d, i| by_key[d[:key]] = widgets[i] if d[:key] }
|
||||
|
||||
{ widgets: widgets, primary: primary, by_key: by_key }
|
||||
end
|
||||
|
||||
def button_width(button)
|
||||
"[ #{button.display_label} ]".length
|
||||
end
|
||||
|
||||
def build_handler(window, app, descriptor)
|
||||
on_click = descriptor[:on_click]
|
||||
keep_open = descriptor[:keep_open]
|
||||
lambda do |_btn|
|
||||
result = on_click&.call(window)
|
||||
app.close_window(window) unless keep_open || result == :keep
|
||||
:handled
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user