Class: WindowAdapter
- Inherits:
-
Object
- Object
- WindowAdapter
- 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
- #brighten(col, bg) ⇒ Object
- #char_h ⇒ Object
- #char_w ⇒ Object
- #clear ⇒ Object
- #clear_area(x, y, w, h) ⇒ Object
- #clear_cells(x, y, w, h) ⇒ Object
- #clear_line(y, from_x, to_x = nil) ⇒ Object
- #delete_lines(y, num, maxy) ⇒ Object
-
#dim(col) ⇒ Object
FIXME.
- #draw(x, y, c, fg, bg, flags, lineattrs) ⇒ Object
-
#draw_flag_lines(flags, x, y, len, fg) ⇒ Object
Migrating draw_flush.
-
#initialize(window, term) ⇒ WindowAdapter
constructor
A new instance of WindowAdapter.
- #insert_lines(y, num, maxy) ⇒ Object
-
#redraw_all ⇒ Object
Force a complete redraw of the window contents.
-
#scroll_selection(start, bottom) ⇒ Object
A line of the scroll region [start..bottom] has moved into history.
- #scroll_up(scroll_start, scroll_end) ⇒ Object
-
#scrollback_anchor ⇒ Object
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.
-
#scrollback_mode ⇒ Object
True while the view is scrolled back into history.
-
#set_columns(cols) ⇒ Object
DECCOLM: the terminal asked to switch to
colscolumns (80/132).
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
53 54 55 56 |
# File 'lib/windowadapter.rb', line 53 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_h ⇒ Object
20 |
# File 'lib/windowadapter.rb', line 20 def char_h = @window.char_h |
#char_w ⇒ Object
19 |
# File 'lib/windowadapter.rb', line 19 def char_w = @window.char_w |
#clear ⇒ Object
21 |
# File 'lib/windowadapter.rb', line 21 def clear = @window.clear(0,0,@window.width,@window.height) |
#clear_area(x, y, w, h) ⇒ Object
58 |
# File 'lib/windowadapter.rb', line 58 def clear_area(x,y,w,h) = @window.clear(x*char_w,y*char_h,w,h) |
#clear_cells(x, y, w, h) ⇒ Object
59 |
# File 'lib/windowadapter.rb', line 59 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
61 62 63 64 65 66 67 68 69 70 |
# File 'lib/windowadapter.rb', line 61 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
88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/windowadapter.rb', line 88 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
49 50 51 |
# File 'lib/windowadapter.rb', line 49 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
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/windowadapter.rb', line 123 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
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/windowadapter.rb', line 105 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
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/windowadapter.rb', line 72 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_all ⇒ Object
Force a complete redraw of the window contents
151 152 153 154 155 156 157 158 |
# File 'lib/windowadapter.rb', line 151 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_selection(start, bottom) ⇒ Object
A line of the scroll region [start..bottom] has moved into history. Forward to the orchestrator so it can keep a live text selection pinned to the content it covers. The headless harness/bench hosts have no selection state and do not implement this, so it no-ops there.
37 38 39 |
# File 'lib/windowadapter.rb', line 37 def scroll_selection(start, bottom) @term.shift_selection_for_scroll(start, bottom) if @term.respond_to?(:shift_selection_for_scroll) end |
#scroll_up(scroll_start, scroll_end) ⇒ Object
161 162 163 164 165 166 167 168 |
# File 'lib/windowadapter.rb', line 161 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_anchor ⇒ Object
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_mode ⇒ Object
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.
45 46 47 |
# File 'lib/windowadapter.rb', line 45 def set_columns(cols) @term.set_columns(cols) if @term.respond_to?(:set_columns) end |