Class: Potty::View

Inherits:
Object
  • Object
show all
Defined in:
lib/potty/view.rb

Overview

Base class for views

Direct Known Subclasses

Mouth::Prompt::Base

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app) ⇒ View

Returns a new instance of View.



11
12
13
14
15
16
# File 'lib/potty/view.rb', line 11

def initialize(app)
  @app = app
  @widgets = []
  @focused_index = 0
  build_layout
end

Instance Attribute Details

#appObject (readonly)

Returns the value of attribute app.



9
10
11
# File 'lib/potty/view.rb', line 9

def app
  @app
end

#widgetsObject (readonly)

Returns the value of attribute widgets.



9
10
11
# File 'lib/potty/view.rb', line 9

def widgets
  @widgets
end

Instance Method Details

#activate(app) ⇒ Object



18
19
20
21
22
# File 'lib/potty/view.rb', line 18

def activate(app)
  @app = app
  on_activate
  layout_widgets
end

#build_layoutObject

Override to build widget tree



32
33
34
# File 'lib/potty/view.rb', line 32

def build_layout
  # Override in subclasses
end

#deactivateObject



24
25
26
# File 'lib/potty/view.rb', line 24

def deactivate
  on_deactivate
end

#handle_escapeObject



90
91
92
# File 'lib/potty/view.rb', line 90

def handle_escape
  false  # Return true if handled
end

#handle_key(ch) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/potty/view.rb', line 69

def handle_key(ch)
  # Delegate to focused widget first
  return true if focused_widget&.handle_key(ch)

  # Handle view-level keys. Enter advances focus like Tab when the
  # focused widget didn't consume it — so a form flows field -> field ->
  # button (where the button finally consumes Enter and fires). A view
  # that wants Enter for itself (e.g. a prompt that submits) intercepts it
  # before delegating to super.
  case ch
  when Keys::TAB, *Keys::ENTERS
    cycle_focus(1)
    true
  when Keys::SHIFT_TAB
    cycle_focus(-1)
    true
  else
    false
  end
end

#layout_widgetsObject



36
37
38
39
40
41
42
43
44
45
46
# File 'lib/potty/view.rb', line 36

def layout_widgets
  rows, cols = @app.surface.size
  container = Layout::Rect.new(0, 0, cols, rows)

  # Simple stack layout. Override #spacing to pack tighter — inline views
  # in particular want 0 so their height matches the region exactly.
  rects = Layout.stack(container, @widgets, spacing: spacing)
  @widgets.zip(rects).each do |widget, rect|
    widget.layout(rect)
  end
end

#on_activateObject



28
# File 'lib/potty/view.rb', line 28

def on_activate; end

#on_deactivateObject



29
# File 'lib/potty/view.rb', line 29

def on_deactivate; end

#renderObject

Draw the widget tree onto the application’s surface. The surface frame (erase/present) is owned by Application#refresh_all, so this just paints.



56
57
58
59
60
61
# File 'lib/potty/view.rb', line 56

def render
  surface = @app.surface
  @widgets.each do |widget|
    widget.render(surface)
  end
end

#spacingObject

Rows of blank space the default layout leaves between top-level widgets. Override to change it (e.g. 0 for a tightly-packed inline region).



50
51
52
# File 'lib/potty/view.rb', line 50

def spacing
  1
end

#tick(now) ⇒ Object

Fan a time tick out to top-level widgets. Driven by Application#tick when a tick_interval is set. ‘now` is one Time read per frame.



65
66
67
# File 'lib/potty/view.rb', line 65

def tick(now)
  @widgets.each { |widget| widget.tick(now) }
end