Class: MarsBase10::Pane

Inherits:
Object
  • Object
show all
Defined in:
lib/mars_base_10/pane.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(viewport:, at_row:, at_col:, height_pct: 1, width_pct: 1) ⇒ Pane



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/mars_base_10/pane.rb', line 9

def initialize(viewport:, at_row:, at_col:, height_pct: 1, width_pct: 1)
  @first_visible_index   = 1
  @height_pct            = height_pct
  @highlight             = false
  @index                 = 1
  @last_visible_index    = 0
  @latch                 = ''
  @latch_depth           = 0
  @left_edge_col         = at_col
  @subject               = nil
  @top_row               = at_row
  @win                   = nil
  @viewport              = viewport
  # @visible_content_shift = 0
  @width_pct             = width_pct
end

Instance Attribute Details

#cur_draw_colObject

Returns the value of attribute cur_draw_col.



6
7
8
# File 'lib/mars_base_10/pane.rb', line 6

def cur_draw_col
  @cur_draw_col
end

#cur_draw_rowObject

Returns the value of attribute cur_draw_row.



6
7
8
# File 'lib/mars_base_10/pane.rb', line 6

def cur_draw_row
  @cur_draw_row
end

#extended_linesObject

Returns the value of attribute extended_lines.



6
7
8
# File 'lib/mars_base_10/pane.rb', line 6

def extended_lines
  @extended_lines
end

#height_pctObject (readonly)

Returns the value of attribute height_pct.



7
8
9
# File 'lib/mars_base_10/pane.rb', line 7

def height_pct
  @height_pct
end

#highlightObject

Returns the value of attribute highlight.



6
7
8
# File 'lib/mars_base_10/pane.rb', line 6

def highlight
  @highlight
end

#indexObject

Returns the value of attribute index.



6
7
8
# File 'lib/mars_base_10/pane.rb', line 6

def index
  @index
end

#latchObject

Returns the value of attribute latch.



6
7
8
# File 'lib/mars_base_10/pane.rb', line 6

def latch
  @latch
end

#left_edge_colObject (readonly)

Returns the value of attribute left_edge_col.



7
8
9
# File 'lib/mars_base_10/pane.rb', line 7

def left_edge_col
  @left_edge_col
end

#subjectObject

Returns the value of attribute subject.



6
7
8
# File 'lib/mars_base_10/pane.rb', line 6

def subject
  @subject
end

#top_rowObject (readonly)

Returns the value of attribute top_row.



7
8
9
# File 'lib/mars_base_10/pane.rb', line 7

def top_row
  @top_row
end

#viewportObject (readonly)

Returns the value of attribute viewport.



7
8
9
# File 'lib/mars_base_10/pane.rb', line 7

def viewport
  @viewport
end

#width_pctObject (readonly)

Returns the value of attribute width_pct.



7
8
9
# File 'lib/mars_base_10/pane.rb', line 7

def width_pct
  @width_pct
end

Instance Method Details

#active?Boolean



26
27
28
# File 'lib/mars_base_10/pane.rb', line 26

def active?
  self == self.viewport.active_pane
end

#clearObject



30
31
32
33
34
35
36
37
38
39
# File 'lib/mars_base_10/pane.rb', line 30

def clear
  self.reset
  self.prepare_for_writing_contents
  (0..(self.last_row - 1)).each do |item|
    self.window.setpos(self.cur_draw_row, self.cur_draw_col)
    self.window.addstr("")
    self.window.clrtoeol
    self.cur_draw_row += 1
  end
end

#current_item_indexObject



41
42
43
# File 'lib/mars_base_10/pane.rb', line 41

def current_item_index
  (self.cur_draw_row - self.extended_lines) + self.visible_content_shift
end

#current_subject_indexObject



45
46
47
# File 'lib/mars_base_10/pane.rb', line 45

def current_subject_index
  self.subject.at(index: self.index)
end

#drawObject



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/mars_base_10/pane.rb', line 49

def draw
  self.prepare_for_writing_contents

  while self.cur_draw_row <= self.last_drawable_row
    if self.current_item_index <= self.subject.item_index_range.last
      if (self.current_item_index == self.index) && !self.highlight
        self.window.attron(Curses::A_REVERSE)
        self.highlight = true
      end

      if self.subject.line_length_at(index: self.current_item_index) > self.last_col
        chunks = self.subject.line_at(index: self.current_item_index).chars.each_slice(self.last_col - 2).map(&:join)
        chunks.each do |c|
          self.draw_line
          self.window.addstr("#{c}")
          self.cur_draw_row += 1
          self.extended_lines += 1
        end
        self.extended_lines -= 1
      else
        self.draw_line
        self.window.addstr("#{self.subject.line_at(index: self.current_item_index)}")
        self.cur_draw_row += 1
      end

      if self.highlight
        self.window.attroff(Curses::A_REVERSE)
        self.highlight = false
      end
    else
      self.draw_line
      self.window.addstr(" ")
      self.cur_draw_row += 1
    end
    self.window.clrtoeol
  end
  self.draw_border

  @last_visible_index = self.current_item_index - 1  # Subtract one b/c we have already incremented before loop
end

#draw_borderObject



90
91
92
93
94
95
# File 'lib/mars_base_10/pane.rb', line 90

def draw_border
  self.window.attron(Curses.color_pair(1) | Curses::A_BOLD) if self.active?
  self.window.box
  self.draw_title
  self.window.attroff(Curses.color_pair(1) | Curses::A_BOLD) if self.active?
end

#draw_lineObject



97
98
99
# File 'lib/mars_base_10/pane.rb', line 97

def draw_line
  self.window.setpos(self.cur_draw_row, self.cur_draw_col)
end

#draw_titleObject



101
102
103
104
# File 'lib/mars_base_10/pane.rb', line 101

def draw_title
  self.window.setpos(0, 2)
  self.window.addstr(" #{self.subject.title} (#{self.max_contents_rows} total) ")
end

#first_drawable_colObject



106
107
108
# File 'lib/mars_base_10/pane.rb', line 106

def first_drawable_col
  1
end

#first_drawable_rowObject



110
111
112
# File 'lib/mars_base_10/pane.rb', line 110

def first_drawable_row
  1
end

#gutter_widthObject



114
115
116
# File 'lib/mars_base_10/pane.rb', line 114

def gutter_width
  self.subject.index_width
end

#last_colObject

This is the relative last column, e.g. the width of the pane in columns.



121
122
123
124
# File 'lib/mars_base_10/pane.rb', line 121

def last_col
  # [(self.viewport.max_cols * self.width_pct).floor, self.min_column_width].max
  (self.viewport.max_cols * self.width_pct).floor
end

#last_drawable_rowObject



126
127
128
# File 'lib/mars_base_10/pane.rb', line 126

def last_drawable_row
  [self.last_visible_row, self.max_contents_rows].min
end

#last_rowObject

This is the relative last row, e.g. the height of the pane in rows



133
134
135
# File 'lib/mars_base_10/pane.rb', line 133

def last_row
  (self.viewport.max_rows * self.height_pct).floor
end

#last_visible_rowObject

This is the height of the pane minus the border



140
141
142
# File 'lib/mars_base_10/pane.rb', line 140

def last_visible_row
  self.last_row - 2
end

#latched?Boolean

The pane is latched if it has consumed 1 key 0-9 and is awaiting the next key.



147
148
149
# File 'lib/mars_base_10/pane.rb', line 147

def latched?
  @latch_depth > 0
end

#max_contents_rowsObject



151
152
153
# File 'lib/mars_base_10/pane.rb', line 151

def max_contents_rows
  self.subject.item_index_range.last
end

#min_column_widthObject



155
156
157
# File 'lib/mars_base_10/pane.rb', line 155

def min_column_width
  self.gutter_width + self.subject.max_content_width + self.right_pad
end

#prepare_for_writing_contentsObject



159
160
161
162
163
164
165
# File 'lib/mars_base_10/pane.rb', line 159

def prepare_for_writing_contents
  self.cur_draw_row = self.first_drawable_row
  self.cur_draw_col = self.first_drawable_col
  self.extended_lines = 0
  @first_visible_index = self.cur_draw_row + self.visible_content_shift
  @last_visible_index = self.subject.item_count if @last_visible_index < @first_visible_index
end

#processObject

process blocks and waits for a keypress.

this method handles only the “default” keypresses which all controllers/subjects

must support. Any unrecognized key is bubbled to the controller for more specific
handling.


174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/mars_base_10/pane.rb', line 174

def process
  key = self.window.getch.to_s
  case key
  when 'j'
    self.index = self.set_row(self.index + 1)
  when 'k'
    self.index = self.set_row(self.index - 1)
  when 'J'
    self.index = self.set_row([self.index + (self.last_visible_row), self.max_contents_rows].min)
  when 'K'
    self.index = self.set_row(self.index - self.visible_content_range.count)
  when 'q'
    exit 0
  when ('0'..'9')
    if self.latched?
      self.latch << key
      @latch_depth += 1
      if @latch_depth == self.gutter_width
        self.index = self.set_row(self.latch.to_i)
        self.latch = ""
        @latch_depth = 0
      end
    else
      self.latch = key
      @latch_depth = 1
    end
  end

  # Always send the key to the controller for additional processing...
  self.viewport.controller.send key: key
end

#resetObject



206
207
208
209
210
211
# File 'lib/mars_base_10/pane.rb', line 206

def reset
  @index = 1
  @latch = ''
  @latch_depth = 0
  # @visible_content_shift = 0
end

#right_padObject



213
214
215
# File 'lib/mars_base_10/pane.rb', line 213

def right_pad
  2
end

#scroll_to_row(index) ⇒ Object



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/mars_base_10/pane.rb', line 217

def scroll_to_row(index)
  jump = [(index - self.index), (self.max_contents_rows - self.visible_content_range.last)].min
  if index > self.index
    # Scrolling down
    if index > self.visible_content_range.last
      @first_visible_index = @first_visible_index + jump
      @last_visible_index = @last_visible_index + jump
    end
  else
    # Scrolling up
    if index < self.visible_content_range.first
        @first_visible_index = [(@first_visible_index + jump), 1].max
        @last_visible_index = @last_visible_index + jump
    end
  end
  [index, 1].max
end

#set_row(i) ⇒ Object

this is a no-op if the index is out of range



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/mars_base_10/pane.rb', line 238

def set_row(i)
  return i if self.visible_content_range.include?(i)

  # If we've reached the end of the content, it's a no-op.
  current_index = self.index
  return self.max_contents_rows if (i > self.max_contents_rows)

  # Check if we have tried to move "above" the visible screen limit (i = 1) and retrieve more items, if possible.
  if (i < 1)
    if i < 0
      target_index = self.index
      self.index = 1
    end
    i = [self.viewport.controller.load_history, 1].max
    i = target_index if target_index
  end

  return self.scroll_to_row(i)
end

#view(subject:) ⇒ Object



258
259
260
# File 'lib/mars_base_10/pane.rb', line 258

def view(subject:)
  @subject = subject
end

#visible_content_rangeObject



262
263
264
265
# File 'lib/mars_base_10/pane.rb', line 262

def visible_content_range
  # ((self.first_drawable_row + @visible_content_shift)..(self.last_drawable_row + @visible_content_shift))
  (@first_visible_index..@last_visible_index)
end

#visible_content_shiftObject



267
268
269
# File 'lib/mars_base_10/pane.rb', line 267

def visible_content_shift
  self.visible_content_range.first - self.first_drawable_row
end

#windowObject



271
272
273
274
# File 'lib/mars_base_10/pane.rb', line 271

def window
  return @win if @win
  @win = Curses::Window.new(self.last_row, self.last_col, self.top_row, self.left_edge_col)
end