Class: WindowAdapter

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

Overview

#Design change:

Terminal writes to the buffer. Buffer batches up updates to an output adapter (the window, but could be a terminal…)

But for now, the now stupidly misnamed TrackChanges class just bifurcates buffer changes and passes them to both the buffer and the screen, and “nothing” should talk to the window directly. Once all window updates are moved to TrackChanges/WindowAdapter We want to make it smarter.

Instance Method Summary collapse

Constructor Details

#initialize(window, term) ⇒ WindowAdapter

Returns a new instance of WindowAdapter.



14
15
16
17
# File 'lib/windowadapter.rb', line 14

def initialize window, term
  @window = window
  @term = term
end

Instance Method Details

#brighten(col, bg) ⇒ Object



45
46
47
48
# File 'lib/windowadapter.rb', line 45

def brighten(col, bg)
  # FIXME. Should bring it towards bg
  [col].pack("l").each_byte.map{|b| (b.ord+128).clamp(0,255) }.pack("C*").unpack("l")[0]
end

#char_hObject



20
# File 'lib/windowadapter.rb', line 20

def char_h = @window.char_h

#char_wObject



19
# File 'lib/windowadapter.rb', line 19

def char_w = @window.char_w

#clearObject



21
# File 'lib/windowadapter.rb', line 21

def clear  = @window.clear(0,0,@window.width,@window.height)

#clear_area(x, y, w, h) ⇒ Object



50
# File 'lib/windowadapter.rb', line 50

def clear_area(x,y,w,h)  = @window.clear(x*char_w,y*char_h,w,h)

#clear_cells(x, y, w, h) ⇒ Object



51
# File 'lib/windowadapter.rb', line 51

def clear_cells(x,y,w,h) = clear_area(x,y, w * char_w, h * char_h)

#clear_line(y, from_x, to_x = nil) ⇒ Object



53
54
55
56
57
58
59
60
61
62
# File 'lib/windowadapter.rb', line 53

def clear_line y, from_x, to_x = nil
  if to_x
    # to_x is an INCLUSIVE end column, matching TermBuffer#clear_line
    # (EL mode 1 clears [0..cursor] inclusive). Clearing to_x-from_x
    # cells left the cursor column itself stale on screen.
    clear_cells(from_x, y, to_x - from_x + 1, 1)
  else
    clear_cells(from_x, y, @term.term_width - from_x, 1)
  end
end

#delete_lines(y, num, maxy) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/windowadapter.rb', line 80

def delete_lines(y, num, maxy)
  # Deleting more lines than the region holds clears [y..maxy] entirely.
  # Without this clamp a large num gave Window#scroll_up a negative height
  # and a negative clear origin that clamped to row 0, wiping lines above
  # the scroll region.
  num = [num, maxy - y + 1].min
  return if num <= 0
  # Move the rows below the deleted block - [y+num .. maxy] - up by num
  # rows, into [y .. maxy-num]; Window#scroll_up clears the vacated rows
  # at the bottom of the region.
  @window.scroll_up((y + num) * char_h, @term.term_width * char_w,
    (maxy - (y + num) + 1) * char_h, num * char_h)
end

#dim(col) ⇒ Object

FIXME



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

def dim(col) #FIXME
  [col].pack("l").each_byte.map{|b| b.ord*0.4 }.pack("C*").unpack("l")[0]
end

#draw(x, y, c, fg, bg, flags, lineattrs) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/windowadapter.rb', line 115

def draw(x,y,c,fg,bg,flags,lineattrs)
  inverse = flags.allbits?(INVERSE)
  if inverse
    fg,bg=bg,fg
  end

  if flags.allbits?(FAINT)
    fg = dim(fg)
  end

  if flags.anybits?(BLINK) && @term.blink_state
    fg = inverse ? brighten(fg,bg) : dim(fg)
  elsif flags.anybits?(RAPID_BLINK) && @term.rblink_state
    fg = inverse ? brighten(fg,bg) : dim(fg)
  end

  if x.nil?
    # @BUG
    STDERR.puts "\e[35m@BUG\[0m: x.nil? @windowadapter#draw"
    return
  end
  
  @window.draw(x*char_w, y*char_h, c, fg, bg, lineattrs)
  # FIXME: Take into account lineattrs
  draw_flag_lines(flags, x, y, c.length, fg)
end

#draw_flag_lines(flags, x, y, len, fg) ⇒ Object

# Migrating draw_flush



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/windowadapter.rb', line 97

def draw_flag_lines(flags, x,y, len, fg)
  x *= char_w
  y *= char_h
  w = len * char_w
  if flags.allbits?(OVERLINE)
    @window.draw_line(x,y,w,fg)
  end
  if flags.allbits?(CROSSED_OUT)
    @window.draw_line(x,y+char_h/2+2, w, fg)
  end
  if flags.anybits?(UNDERLINE | DBL_UNDERLINE)
    @window.draw_line(x,y+char_h-3, w, fg)
    if flags.allbits?(DBL_UNDERLINE)
      @window.draw_line(x,y+char_h-1, w, fg)
    end
  end
end

#insert_lines(y, num, maxy) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/windowadapter.rb', line 64

def insert_lines(y, num, maxy)
  # Inserting more lines than fit between y and the region bottom just
  # blanks the whole [y..maxy] span; clamp so the geometry below never
  # goes negative (which would clear rows above the region - see DL).
  num = [num, maxy - y + 1].min
  return if num <= 0
  # Move the rows from the insertion point down to the region bottom -
  # [y .. maxy-num] - down by num rows, into [y+num .. maxy];
  # Window#scroll_down clears the vacated rows at the top (the inserted
  # blanks). The old code scrolled from screen row 0 and ignored y, so an
  # IL anywhere below the top dragged every line above it (and outside the
  # scroll region) down, blanking row 0.
  @window.scroll_down(y * char_h, @term.term_width * char_w,
    (maxy - y - num + 1) * char_h, num * char_h)
end

#redraw_allObject

Force a complete redraw of the window contents



143
144
145
146
147
148
149
150
# File 'lib/windowadapter.rb', line 143

def redraw_all
  # First clear the entire window
  @window.clear(0, 0, @window.width, @window.height)
  
  # Force the window to flush and update its display
  @window.dirty!
  @window.flush
end

#scroll_up(scroll_start, scroll_end) ⇒ Object



153
154
155
156
157
158
159
160
# File 'lib/windowadapter.rb', line 153

def scroll_up(scroll_start, scroll_end)
  @window.scroll_up(
    char_h*((scroll_start||0)+1),
    @window.width,
    (scroll_end-scroll_start)*char_h,
    char_h
  )
end

#scrollback_anchorObject

A line has entered history while scrolled back: keep the same absolute lines in view (and the selection mapping consistent) by deepening the offset instead of letting the viewport drift.



31
# File 'lib/windowadapter.rb', line 31

def scrollback_anchor = @window.scrollback_anchor

#scrollback_modeObject

True while the view is scrolled back into history. Live (pty-driven) screen writes are suppressed in this state so output doesn’t paint over the scrolled-back display; the buffer is still updated underneath.



26
# File 'lib/windowadapter.rb', line 26

def scrollback_mode = @window.scrollback_mode

#set_columns(cols) ⇒ Object

DECCOLM: the terminal asked to switch to cols columns (80/132). The orchestrator (RubyTerm) owns the window pixels, font scale, config and the pty size report, so delegate to it. The headless harness “term” does not implement this (the virtual grid is fixed), so it no-ops.



37
38
39
# File 'lib/windowadapter.rb', line 37

def set_columns(cols)
  @term.set_columns(cols) if @term.respond_to?(:set_columns)
end