class BBS::Windows::MasterDetail
A two-pane browser: left ListBox of items, right ScrollView of details. Selecting an item in the list reloads the detail pane.
BBS::Windows::MasterDetail.open(app,
title: ' Game Catalog ',
items: services[:games].all,
item_label: ->(g) { g.title },
list_width: 30,
render_detail: ->(game, width) { GameCard.lines(game, width) },
actions: [
{ label: '&New', on_click: ->(win) { ... } }
],
bottom_meta: ->(item) { "...optional 1-line meta..." }
)
render_detail is called with (item, width) whenever the selection changes and on first paint. It must return an Array of strings (each one is one rendered line; ANSI is supported). Returning nil shows nothing.
bottom_meta is optional; if given, itโs a ->(item) { text } lambda for a single info line below the detail pane.
actions: are extra buttons (right-aligned by default). A Close button is always appended on the right unless the caller suppresses it via close_button: false.
on_activate is optional: ->(item, window) { ... }, called when the caller presses Enter on a list item. replace_items swaps the list in place (a file browser changing folders) and selects the first item.
Constants
- OPTIONS
-
The options of
::newand their defaults.
Attributes
The BBS::Widgets::ListBox of items, the BBS::Widgets::ScrollView of details, and the BBS::Widgets::Label of the meta line (nil without bottom_meta).
The BBS::Widgets::ListBox of items, the BBS::Widgets::ScrollView of details, and the BBS::Widgets::Label of the meta line (nil without bottom_meta).
The BBS::Widgets::ListBox of items, the BBS::Widgets::ScrollView of details, and the BBS::Widgets::Label of the meta line (nil without bottom_meta).
Public Class Methods
# File lib/bbs/windows/master_detail.rb, line 84 def initialize(app:, title:, items:, item_label:, render_detail:, **options) unknown = options.keys - OPTIONS.keys raise ArgumentError, "unknown master/detail options: #{unknown.inspect}" unless unknown.empty? @options = OPTIONS.merge(options) super(title: title, modal: false, maximizable: @options[:maximizable]) self.theme = app.theme @app = app @item_label = item_label @render_detail = render_detail @actions = actions build(items) end
Creates the window and its panes, centred on appโs screen. It is not opened; see attach.
- app
-
the
BBS::Application - title
-
the window title
- items
-
the Array of items in the list
- item_label
-
called with an item, returns its list text
- render_detail
-
called with
(item, width), returns the detail lines
The options (OPTIONS):
- list_width
-
the list pane width; by default a third of the window, 20 to 40 columns
- bottom_meta
-
called with an item, returns the meta line text
- actions
-
an Array of
BBS::Windows::ButtonBardescriptors - on_activate
-
called with
(item, window)on Enter - close_button
-
appends a Close button (default true)
- close_label
-
the Close buttonโs label
- empty_message
-
the detail text when nothing is selected
- width
-
the window width; by default the screen less 4
- height
-
the window height; by default the screen less 6
- maximizable
-
gives the window the zoom gadget
Raises ArgumentError for an unknown option.
BBS::Window::new
Source
# File lib/bbs/windows/master_detail.rb, line 50 def self.open(app, **) new(app: app, **).tap(&:attach) end
Creates a master/detail window with the keywords of MasterDetail.new and opens it on app.
Returns the MasterDetail window.
Public Instance Methods
Source
# File lib/bbs/windows/master_detail.rb, line 102 def attach @app.open_window(self) reset_focus focus_manager.focus(@list_widget) reload_detail self end
Opens the window on the application, focuses the list, and renders the detail of the selected item.
Returns self.
Source
# File lib/bbs/windows/master_detail.rb, line 139 def normal_rect w = @options[:width] || (@app.cols - 4) h = @options[:height] || (@app.rows - 6) [((@app.cols - w) / 2) + 1, ((@app.rows - h) / 2) + 1, w, h] end
Returns the un-maximized bounds as [x, y, width, height]: the requested size, or the screen less 4 columns and 6 rows, centred.
Source
# File lib/bbs/windows/master_detail.rb, line 147 def place(x, y, width, height) layout(x, y, width, height) place_panes ButtonBar.place(self, @bar[:widgets], @actions) keep_selection_in_sight reload_detail(keep_scroll: true) end
Lays the window out at the given size (terminal resized, maximized, restored) and re-renders the detail at the new pane width.
# File lib/bbs/windows/master_detail.rb, line 114 def reload_detail(keep_scroll: false) item = @list_widget.selected_item scroll = keep_scroll && item ? @detail_view.scroll : 0 @detail_view.lines = detail_lines(item) @detail_view.scroll = scroll.clamp(0, [@detail_view.lines.size - @detail_view.bounds.height, 0].max) @meta_label&.text = item ? @options[:bottom_meta].call(item) : '' end
Renders the selected item into the detail pane and the meta line, or shows the empty message when nothing is selected. With keep_scroll the detail keeps its scroll position (clamped to the new length); otherwise it scrolls to the top.
# File lib/bbs/windows/master_detail.rb, line 124 def replace_items(items, title: nil) @list_widget.items = items @list_widget.selected = 0 @list_widget.scroll = 0 self.title = title if title reload_detail end
Replaces the list with items, selects the first one, and renders its detail. title, when given, becomes the window title.
Source
# File lib/bbs/windows/master_detail.rb, line 134 def resizable? = true
A master/detail window can be resized; place lays the panes out again.