Class: Tuile::Component::Popup
- Inherits:
-
Tuile::Component
- Object
- Tuile::Component
- Tuile::Component::Popup
- Includes:
- HasContent
- Defined in:
- lib/tuile/component/popup.rb
Overview
A modal overlay that wraps any Tuile::Component as its content. Popup itself paints nothing — it’s a transparent host that handles modality (#open / #close / #open?, ESC/q to close), centers itself on the screen, and auto-sizes to the wrapped content.
The wrapped content fills the popup’s full #rect; if you want a frame and caption, wrap a Window (or any subclass — including LogWindow) and let it draw its own border:
window = Component::Window.new("Help")
window.content = Component::List.new.tap { _1.lines = lines }
Component::Popup.new(content: window).open
Bare content also works (a Label, a List…), in which case the popup is borderless.
‘q` and ESC close the popup. Any nested TextField that owns the hardware cursor swallows printable keys first via the standard cursor-owner suppression in #handle_key, so typing `q` into a text field doesn’t dismiss the popup.
Instance Attribute Summary
Attributes included from HasContent
Attributes inherited from Tuile::Component
#content_size, #key_shortcut, #on_theme_changed, #parent, #rect
Class Method Summary collapse
-
.open(content: nil) ⇒ Popup
Constructs and opens a popup in one call.
Instance Method Summary collapse
-
#center ⇒ void
Recenters the popup on the screen, preserving its current width/height.
-
#close ⇒ void
Removes this popup from the Screen.
-
#content=(new_content) ⇒ Object
Sets the popup’s content and auto-sizes the popup to fit.
- #focusable? ⇒ Boolean
-
#handle_key(key) ⇒ Boolean
True if the key was handled.
-
#initialize(content: nil) ⇒ Popup
constructor
A new instance of Popup.
-
#keyboard_hint ⇒ String
Hint for the status bar: own “q Close” plus the wrapped content’s hint.
-
#max_height ⇒ Integer
Max height the popup will grow to fit its content, defaults to 12.
-
#on_child_content_size_changed(_child) ⇒ void
Re-sizes (and recenters, when open) whenever the wrapped content’s natural size changes — e.g.
-
#open ⇒ void
Mounts this popup on the Screen.
-
#open? ⇒ Boolean
True if this popup is currently mounted on the screen.
-
#rect=(new_rect) ⇒ void
Reassigns the popup’s rect, escalating to a full scene repaint when an open popup shrinks or moves so its new rect no longer covers the cells it previously painted.
Methods included from HasContent
#children, #handle_mouse, #on_focus
Methods inherited from Tuile::Component
#active=, #active?, #attached?, #children, #cursor_position, #depth, #find_shortcut_component, #focus, #handle_mouse, #on_child_removed, #on_focus, #on_tree, #repaint, #root, #screen, #tab_stop?
Constructor Details
#initialize(content: nil) ⇒ Popup
Returns a new instance of Popup.
30 31 32 33 34 |
# File 'lib/tuile/component/popup.rb', line 30 def initialize(content: nil) super() @content = nil self.content = content unless content.nil? end |
Class Method Details
Instance Method Details
#center ⇒ void
This method returns an undefined value.
Recenters the popup on the screen, preserving its current width/height. Called automatically by the screen’s layout pass and by #content= when the popup is open.
84 85 86 |
# File 'lib/tuile/component/popup.rb', line 84 def center self.rect = rect.centered(screen.size) end |
#close ⇒ void
This method returns an undefined value.
Removes this popup from the Screen. No-op if not currently open.
71 72 73 |
# File 'lib/tuile/component/popup.rb', line 71 def close screen.remove_popup(self) end |
#content=(new_content) ⇒ Object
Sets the popup’s content and auto-sizes the popup to fit.
94 95 96 97 |
# File 'lib/tuile/component/popup.rb', line 94 def content=(new_content) super update_rect unless new_content.nil? end |
#focusable? ⇒ Boolean
36 |
# File 'lib/tuile/component/popup.rb', line 36 def focusable? = true |
#handle_key(key) ⇒ Boolean
Returns true if the key was handled.
119 120 121 122 123 124 125 126 127 128 |
# File 'lib/tuile/component/popup.rb', line 119 def handle_key(key) return true if super if [Keys::ESC, "q"].include?(key) close true else false end end |
#keyboard_hint ⇒ String
Hint for the status bar: own “q Close” plus the wrapped content’s hint.
111 112 113 114 115 |
# File 'lib/tuile/component/popup.rb', line 111 def keyboard_hint prefix = "q #{screen.theme.hint("Close")}" child_hint = @content&.keyboard_hint.to_s child_hint.empty? ? prefix : "#{prefix} #{child_hint}" end |
#max_height ⇒ Integer
Returns max height the popup will grow to fit its content, defaults to 12. Override in a subclass to allow taller popups.
90 |
# File 'lib/tuile/component/popup.rb', line 90 def max_height = 12 |
#on_child_content_size_changed(_child) ⇒ void
This method returns an undefined value.
Re-sizes (and recenters, when open) whenever the wrapped content’s natural size changes — e.g. a Label‘s `text=`, a List’s ‘add_line`, or a nested Window whose own content grew (the window recomputes its Tuile::Component#content_size and the change bubbles here).
105 106 107 |
# File 'lib/tuile/component/popup.rb', line 105 def on_child_content_size_changed(_child) update_rect end |
#open ⇒ void
This method returns an undefined value.
Mounts this popup on the Screen. Recomputes the popup’s size from the current content first, so reopening a popup whose content has grown or shrunk while closed picks up the new size.
57 58 59 60 |
# File 'lib/tuile/component/popup.rb', line 57 def open update_rect unless @content.nil? screen.add_popup(self) end |
#open? ⇒ Boolean
Returns true if this popup is currently mounted on the screen.
76 77 78 |
# File 'lib/tuile/component/popup.rb', line 76 def open? screen.has_popup?(self) end |
#rect=(new_rect) ⇒ void
This method returns an undefined value.
Reassigns the popup’s rect, escalating to a full scene repaint when an open popup shrinks or moves so its new rect no longer covers the cells it previously painted. A popup overdraws the scene without clipping and nothing clears underneath it, so Screen#repaint‘s popup-only fast path would repaint into the new rect and leave the vacated cells showing stale content. When the new rect fully covers the old one (the popup only grew), the fast path is correct and the full repaint is skipped.
47 48 49 50 51 |
# File 'lib/tuile/component/popup.rb', line 47 def rect=(new_rect) old_rect = rect super screen.needs_full_repaint if open? && !new_rect.contains_rect?(old_rect) end |