Class: Tuile::Component

Inherits:
Object
  • Object
show all
Defined in:
lib/tuile/component.rb,
lib/tuile/component/list.rb,
lib/tuile/component/label.rb,
lib/tuile/component/popup.rb,
lib/tuile/component/layout.rb,
lib/tuile/component/window.rb,
lib/tuile/component/log_window.rb,
lib/tuile/component/text_field.rb,
lib/tuile/component/has_content.rb,
lib/tuile/component/info_window.rb,
lib/tuile/component/picker_window.rb

Overview

A UI component which is positioned on the screen and draws characters into its bounding rectangle (in #repaint).

Component is considered invisible if #rect is empty or one of left/top is negative. The component won’t draw when invisible.

Direct Known Subclasses

Label, Layout, List, Popup, TextField, Window, ScreenPane

Defined Under Namespace

Modules: HasContent Classes: InfoWindow, Label, Layout, List, LogWindow, PickerWindow, Popup, TextField, Window

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeComponent

Returns a new instance of Component.



10
11
12
13
# File 'lib/tuile/component.rb', line 10

def initialize
  @rect = Rect.new(0, 0, 0, 0)
  @active = false
end

Instance Attribute Details

#key_shortcutString?

A global keyboard shortcut. When pressed, will focus this component.

Returns:

  • (String, nil)

    shortcut, ‘nil` by default.



81
82
83
# File 'lib/tuile/component.rb', line 81

def key_shortcut
  @key_shortcut
end

#parentComponent?

Returns the parent component or nil if the component has no parent.

Returns:

  • (Component, nil)

    the parent component or nil if the component has no parent.



131
132
133
# File 'lib/tuile/component.rb', line 131

def parent
  @parent
end

#rectRect

Returns the rectangle the component occupies on screen.

Returns:

  • (Rect)

    the rectangle the component occupies on screen.



16
17
18
# File 'lib/tuile/component.rb', line 16

def rect
  @rect
end

Instance Method Details

#active=(active) ⇒ void

This method returns an undefined value.

Parameters:

  • active (Boolean)

    true if active. Set by Screen#focused= as it marks the focus chain (root → focused); not meant to be called directly.



111
112
113
114
115
116
117
# File 'lib/tuile/component.rb', line 111

def active=(active)
  active = active ? true : false
  return unless @active != active

  @active = active
  invalidate
end

#active?Boolean

Returns true if the component is on the active chain — i.e. it is the focused component or an ancestor of it. Set by Screen#focused=.

Returns:

  • (Boolean)

    true if the component is on the active chain — i.e. it is the focused component or an ancestor of it. Set by Screen#focused=.



106
# File 'lib/tuile/component.rb', line 106

def active? = @active

#attached?Boolean

Returns true if this component’s tree is currently mounted on the Screen, i.e. its root is the ScreenPane.

Returns:

  • (Boolean)

    true if this component’s tree is currently mounted on the Screen, i.e. its root is the ScreenPane.



161
# File 'lib/tuile/component.rb', line 161

def attached? = root == screen.pane

#childrenArray<Component>

List of child components, defaults to an empty array.

Returns:

  • (Array<Component>)

    child components. Must not be mutated! May be empty.



143
# File 'lib/tuile/component.rb', line 143

def children = []

#content_sizeSize

The Size big enough to show the entire component contents without scrolling. Plain components have no intrinsic content and report Size::ZERO; container/decorative components (e.g. Label, List, Layout, Window) override this to fold in their content’s natural extent. Used by callers like Popup to auto-size to whatever content was assigned, regardless of its concrete type.

Returns:



194
# File 'lib/tuile/component.rb', line 194

def content_size = Size::ZERO

#cursor_positionPoint?

Where the hardware terminal cursor should sit when this component is the cursor owner. Returns ‘nil` to indicate the cursor should be hidden. The Screen positions the hardware cursor after each repaint cycle by consulting the Screen#focused component only.

Returns:

  • (Point, nil)

    absolute screen coordinates, or nil to hide.



201
# File 'lib/tuile/component.rb', line 201

def cursor_position = nil

#depthInteger

Returns the distance from the root component; 0 if #parent is nil.

Returns:

  • (Integer)

    the distance from the root component; 0 if #parent is nil.



135
# File 'lib/tuile/component.rb', line 135

def depth = parent.nil? ? 0 : parent.depth + 1

#find_shortcut_component(key) ⇒ Component?

Returns the component whose #key_shortcut matches ‘key`, or nil.

Parameters:

  • key (String)

    keyboard key to look up.

Returns:



86
87
88
89
90
91
92
93
94
# File 'lib/tuile/component.rb', line 86

def find_shortcut_component(key)
  return self if key_shortcut == key

  children.each do |child|
    sc = child.find_shortcut_component(key)
    return sc unless sc.nil?
  end
  nil
end

#focusvoid

This method returns an undefined value.

Focuses this component. Equivalent to ‘screen.focused = self`.



43
44
45
# File 'lib/tuile/component.rb', line 43

def focus
  screen.focused = self
end

#focusable?Boolean

Whether this component is a valid focus target. ‘false` by default —passive components like Label are decoration and don’t accept focus. The flag gates click-to-focus (#handle_mouse) and the focus-cascade in container components (Tuile::Component::HasContent#on_focus, Tuile::Component::Layout#on_focus). Independent from #active?: every component carries the active flag, but only focusable ones can become a focus target that puts themselves and their ancestors on the active chain.

Returns:

  • (Boolean)

    true if this component can be focused.



127
# File 'lib/tuile/component.rb', line 127

def focusable? = false

#handle_key(key) ⇒ Boolean

Called when a character is pressed on the keyboard.

Also called for inactive components. Inactive component should just return false.

Default implementation searches for a component with #key_shortcut and focuses it. The shortcut search is suppressed while the focused component owns the hardware cursor (e.g. a TextField the user is typing into) so that hotkeys don’t steal printable keys from the editor.

Parameters:

  • key (String)

    a key.

Returns:

  • (Boolean)

    true if the key was handled, false if not.



67
68
69
70
71
72
73
74
75
76
77
# File 'lib/tuile/component.rb', line 67

def handle_key(key)
  return false unless screen.cursor_position.nil?

  c = find_shortcut_component(key)
  if !c.nil?
    screen.focused = c
    true
  else
    false
  end
end

#handle_mouse(event) ⇒ void

This method returns an undefined value.

Handles mouse event. Default implementation focuses this component when clicked (if #focusable?).

Parameters:



100
101
102
# File 'lib/tuile/component.rb', line 100

def handle_mouse(event)
  screen.focused = self unless event.button != :left || active? || !focusable?
end

#keyboard_hintString

Returns formatted keyboard hint surfaced in the status bar by Screen when this component is the active tiled window or the topmost popup. Empty by default; override to advertise shortcuts.

Returns:

  • (String)

    formatted keyboard hint surfaced in the status bar by Screen when this component is the active tiled window or the topmost popup. Empty by default; override to advertise shortcuts.



206
# File 'lib/tuile/component.rb', line 206

def keyboard_hint = ""

#on_child_removed(child) ⇒ void

This method returns an undefined value.

Called by container components after ‘child` has been detached from `self.children` (its `parent` is already nil and it is no longer in the children list). Default behavior repairs dangling focus: if the focused component lived inside the removed subtree, focus shifts to `self` so the cursor doesn’t dangle on a detached component. No-op if ‘self` is not attached to the screen — focus state in a detached subtree is moot.

Parameters:

  • child (Component)

    the just-detached child.



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/tuile/component.rb', line 171

def on_child_removed(child)
  return unless attached?

  f = screen.focused
  return if f.nil?

  cursor = f
  until cursor.nil?
    if cursor == child
      screen.focused = self
      return
    end
    cursor = cursor.parent
  end
end

#on_focusvoid

This method returns an undefined value.

Called when the component receives focus.



157
# File 'lib/tuile/component.rb', line 157

def on_focus; end

#on_tree {|component| ... } ⇒ void

This method returns an undefined value.

Calls block for this component and for every descendant component.

Yields:

  • (component)

Yield Parameters:

Yield Returns:

  • (void)


150
151
152
153
# File 'lib/tuile/component.rb', line 150

def on_tree(&block)
  block.call(self)
  children.each { it.on_tree(&block) }
end

#repaintvoid

This method returns an undefined value.

Repaints the component. Default implementation does nothing.

The component must fully draw over #rect, and must not draw outside of #rect.

Tip: use #clear_background to clear component background before painting.



54
# File 'lib/tuile/component.rb', line 54

def repaint; end

#rootComponent

Returns the root component of this component hierarchy.

Returns:

  • (Component)

    the root component of this component hierarchy.



138
# File 'lib/tuile/component.rb', line 138

def root = parent.nil? ? self : parent.root

#screenScreen

Returns the screen which owns this component.

Returns:

  • (Screen)

    the screen which owns this component.



39
# File 'lib/tuile/component.rb', line 39

def screen = Screen.instance