module RETerm::NavInput
Helper mixin defining standard navigation controls. Used by layouts and top level components this tightly defines keyboard navigation and allows the user to seemlessly move between and activate/decativate components.
Attributes
Used internally to specify which movement command we should follow
Public Instance Methods
Return children which are focusabled/activable
# File lib/reterm/mixins/nav_input.rb, line 20 def focusable children.select { |c| c.activatable? } end
Return boolean indicating if any children are focusable
# File lib/reterm/mixins/nav_input.rb, line 25 def focusable? !focusable.empty? end
Helper to be internally invoked by navigation component on activation
# File lib/reterm/mixins/nav_input.rb, line 37 def handle_input(from_parent=false) @focus ||= 0 # focus on first component ch = handle_focused unless nav_select # Repeat until quit until quit_nav?(ch) # Navigate to the specified component (nav_select) if self.nav_select # it is a descendent of this one if self.contains?(self.nav_select) nav_to_selected # specified component is not a descendent, else nav_to_parent return nil end elsif ENTER_CONTROLS.include?(ch) focused.activate! elsif MOVEMENT_CONTROLS.include?(ch) handle_movement(ch, from_parent) elsif mev = process_mouse(ch) handle_mouse(mev) else dispatch(:entry, ch) end return ch unless sanitize_focus!(from_parent) ch = handle_focused unless nav_select || shutdown? || deactivate? end ch end
May be overridden by subclass to indicate if the specified input / context is valid
# File lib/reterm/mixins/nav_input.rb, line 31 def valid_input?(ch, from_parent) true end
Private Instance Methods
# File lib/reterm/mixins/nav_input.rb, line 106 def draw_focus! focused.window.border! if !!focused && focused.highlight_focus? end
# File lib/reterm/mixins/nav_input.rb, line 101 def focused return nil unless !!@focus focusable[@focus] end
Internal helper, logic invoked when a component gains focus
# File lib/reterm/mixins/nav_input.rb, line 118 def handle_focused ch = nil focused.dispatch :focused update_focus if focused.activate_focus? focused.activate! elsif focused.kind_of?(Layout) ch = focused.handle_input(true) elsif !deactivate? && !nav_select ch = sync_getch end if self.ch_select ch = self.ch_select self.ch_select = nil end ch end
# File lib/reterm/mixins/nav_input.rb, line 199 def handle_mouse(mev) child = window.root.child_containing(mev.x, mev.y, mev.z) if child child = child.component if child.activatable? if self.contains?(child) nav_to_selected else self.nav_select = child nav_to_parent return nil end end end end
# File lib/reterm/mixins/nav_input.rb, line 84 def handle_movement(ch, from_parent) remove_focus return ch unless valid_input?(ch, from_parent) @focus = next_focus(ch) end
# File lib/reterm/mixins/nav_input.rb, line 90 def next_focus(ch) if UP_CONTROLS.include?(ch) || LEFT_CONTROLS.include?(ch) @focus - 1 elsif DOWN_CONTROLS.include?(ch) || RIGHT_CONTROLS.include?(ch) @focus + 1 end end
Internal helper, logic invoked when a component loses focus
# File lib/reterm/mixins/nav_input.rb, line 143 def remove_focus focused.window.no_border! focused.dispatch :unfocused end
Internal helper, sanitize the focus tracker. Return value indicates if sanity is preseved in the context of this component (else we will return to parent)
# File lib/reterm/mixins/nav_input.rb, line 186 def sanitize_focus!(from_parent) if @focus >= focusable.size @focus = focusable.size - 1 return false if from_parent elsif @focus < 0 @focus = 0 return false if from_parent end true end
Internal help, set the visual properties of the focused window
# File lib/reterm/mixins/nav_input.rb, line 111 def update_focus draw_focus! update_reterm window.root.draw! end