window_blessing 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/Guardfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +43 -0
- data/Rakefile +12 -0
- data/bin/buffered_screen_demo.rb +92 -0
- data/bin/color_picker_demo.rb +176 -0
- data/bin/foiled_demo.rb +27 -0
- data/bin/text_editor_demo.rb +292 -0
- data/bin/windowed_screen_demo.rb +71 -0
- data/bin/xterm_screen_demo.rb +33 -0
- data/lib/window_blessing.rb +54 -0
- data/lib/window_blessing/buffer.rb +216 -0
- data/lib/window_blessing/buffered_screen.rb +29 -0
- data/lib/window_blessing/color.rb +71 -0
- data/lib/window_blessing/constants.rb +3 -0
- data/lib/window_blessing/event_manager.rb +75 -0
- data/lib/window_blessing/event_queue.rb +20 -0
- data/lib/window_blessing/evented.rb +19 -0
- data/lib/window_blessing/evented_variable.rb +47 -0
- data/lib/window_blessing/tools.rb +124 -0
- data/lib/window_blessing/version.rb +3 -0
- data/lib/window_blessing/widgets/draggable_background.rb +13 -0
- data/lib/window_blessing/widgets/label.rb +23 -0
- data/lib/window_blessing/widgets/slider.rb +53 -0
- data/lib/window_blessing/widgets/text_field.rb +92 -0
- data/lib/window_blessing/window.rb +273 -0
- data/lib/window_blessing/windowed_screen.rb +53 -0
- data/lib/window_blessing/xterm_event_parser.rb +156 -0
- data/lib/window_blessing/xterm_input.rb +40 -0
- data/lib/window_blessing/xterm_log.rb +7 -0
- data/lib/window_blessing/xterm_output.rb +213 -0
- data/lib/window_blessing/xterm_screen.rb +109 -0
- data/lib/window_blessing/xterm_state.rb +27 -0
- data/spec/buffer_spec.rb +170 -0
- data/spec/color_spec.rb +36 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/tools_spec.rb +142 -0
- data/spec/window_spec.rb +61 -0
- data/window_blessing.gemspec +28 -0
- metadata +226 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
|
2
|
+
module WindowBlessing
|
3
|
+
class XtermInput
|
4
|
+
attr_reader :event_parser
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@event_parser = XtermEventParser.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def read_events
|
11
|
+
events = []
|
12
|
+
if raw = read_pending_input
|
13
|
+
parsed = event_parser.parse(raw)
|
14
|
+
if parsed
|
15
|
+
new_events = parsed.events
|
16
|
+
events += new_events
|
17
|
+
new_events.length
|
18
|
+
else
|
19
|
+
events << {:type => :event_parser_failure, :raw => raw, :failure_info => event_parser.parser_failure_info}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
events
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
def read_pending_input
|
27
|
+
read = nil
|
28
|
+
begin
|
29
|
+
while c = STDIN.read_nonblock(1000)
|
30
|
+
read = read ? read + c : c
|
31
|
+
end
|
32
|
+
rescue Errno::EAGAIN # nothing was ready to be read
|
33
|
+
rescue Errno::EINTR
|
34
|
+
rescue EOFError
|
35
|
+
end
|
36
|
+
read
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,213 @@
|
|
1
|
+
# ref: http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
|
2
|
+
# ref: http://www.vt100.net/docs/vt102-ug/chapter5.html
|
3
|
+
|
4
|
+
module WindowBlessing
|
5
|
+
|
6
|
+
class XtermOutput
|
7
|
+
module SetColor
|
8
|
+
def change_fg(fg)
|
9
|
+
set_fg(fg) if fg!=@current_fg
|
10
|
+
@current_fg = fg
|
11
|
+
end
|
12
|
+
|
13
|
+
def change_bg(bg)
|
14
|
+
set_bg(bg) if bg!=@current_bg
|
15
|
+
@current_bg = bg
|
16
|
+
end
|
17
|
+
|
18
|
+
def set_fg(fg)
|
19
|
+
out "\x1b[38;5;#{fg}m"
|
20
|
+
end
|
21
|
+
|
22
|
+
def set_bg(bg)
|
23
|
+
out "\x1b[48;5;#{bg}m"
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_reader :current_fg, :current_bg
|
27
|
+
|
28
|
+
def set_color(fg, bg=nil)
|
29
|
+
set_fg(fg) if fg
|
30
|
+
set_bg(bg) if bg
|
31
|
+
end
|
32
|
+
|
33
|
+
# fg and bg are r-g-b arrays: [0..255, 0..255, 0..255]
|
34
|
+
# This is not supported by iTerm2: http://code.google.com/p/iterm2/issues/detail?id=218
|
35
|
+
# konsole supports it: https://github.com/robertknight/konsole/blob/master/user-doc/README.moreColors
|
36
|
+
def set_color_24bit(fg, bg=nil)
|
37
|
+
out "\x1b[38;2;#{fg.join(';')}m" if fg
|
38
|
+
out "\x1b[48;2;#{bg.join(';')}m" if bg
|
39
|
+
end
|
40
|
+
|
41
|
+
def reset_color
|
42
|
+
@current_fg = 7
|
43
|
+
@current_bg = 0
|
44
|
+
out "\x1b[0m"
|
45
|
+
end
|
46
|
+
|
47
|
+
def out_color(txt, fg, bg)
|
48
|
+
set_color(fg, bg)
|
49
|
+
out txt
|
50
|
+
reset_color
|
51
|
+
end
|
52
|
+
|
53
|
+
def set_bold; out "\x1b[1m" end
|
54
|
+
def set_underline; out "\x1b[4m" end
|
55
|
+
end
|
56
|
+
include SetColor
|
57
|
+
|
58
|
+
module SetState
|
59
|
+
def show_cursor; out "\e[?25h"; end
|
60
|
+
def hide_cursor; out "\e[?25l"; end
|
61
|
+
|
62
|
+
def enable_mouse; out "\e[?1003h"; end
|
63
|
+
def disable_mouse; out "\e[?1003l"; end
|
64
|
+
|
65
|
+
def enable_focus_events; out "\e[?1004h" end
|
66
|
+
def disable_focus_events; out "\e[?1004l" end
|
67
|
+
|
68
|
+
def enable_utf8; out "\e%G" end
|
69
|
+
def disable_utf8; out "\e%@" end
|
70
|
+
|
71
|
+
def enable_alternate_screen
|
72
|
+
out "\e7"
|
73
|
+
out "\e[?47h"
|
74
|
+
end
|
75
|
+
|
76
|
+
def disable_alternate_screen
|
77
|
+
out "\e[?47l"
|
78
|
+
out "\e8"
|
79
|
+
end
|
80
|
+
|
81
|
+
# TODO: find out what stty raw -echo sends to xterm
|
82
|
+
# INTERNAL NOTE: out "\e[12h" # should turn off echo according to doc, but didn't work
|
83
|
+
# http://stackoverflow.com/questions/174933/how-to-get-a-single-character-without-pressing-enter
|
84
|
+
def echo_off; system "stty raw -echo"; end
|
85
|
+
|
86
|
+
# INTERNAL NOTE: out "\e[12l" # should turn echo back on
|
87
|
+
def echo_on; system "stty -raw echo"; end
|
88
|
+
|
89
|
+
=begin
|
90
|
+
raw may set the following:
|
91
|
+
00830 option(x + "-icrnl", ""); /* map CR to NL on input */
|
92
|
+
00831 option(x + "-ixon", ""); /* enable start/stop output control */
|
93
|
+
00832 option(x + "-opost", ""); /* perform output processing */
|
94
|
+
00833 option(x + "-onlcr", ""); /* Map NL to CR-NL on output */
|
95
|
+
00834 option(x + "-isig", ""); /* enable signals */
|
96
|
+
00835 option(x + "-icanon", "");/* canonical input (erase and kill enabled) */
|
97
|
+
00836 option(x + "-iexten", "");/* enable extended functions */
|
98
|
+
00837 option(x + "-echo", ""); /* enable echoing of input characters */
|
99
|
+
|
100
|
+
=end
|
101
|
+
|
102
|
+
# This seems to work - or at least it does SOMETHING
|
103
|
+
# def insert_mode; out "\e[4m"; end
|
104
|
+
# def replace_mode; out "\e[4l"; end
|
105
|
+
|
106
|
+
end
|
107
|
+
include SetState
|
108
|
+
|
109
|
+
attr_accessor :xterm_state
|
110
|
+
|
111
|
+
def initialize(xterm_state)
|
112
|
+
@xterm_state = xterm_state
|
113
|
+
end
|
114
|
+
|
115
|
+
# cursor 0, 0 is the upper left hand corner
|
116
|
+
# cursor point(0, 0) is also accepted
|
117
|
+
def cursor(loc_or_x, y=nil)
|
118
|
+
loc = y ? point(loc_or_x,y) : loc_or_x
|
119
|
+
out "\e[#{loc.y+1};#{loc.x+1}H"
|
120
|
+
end
|
121
|
+
|
122
|
+
# raw screen output
|
123
|
+
def out(str)
|
124
|
+
$stdout.print str
|
125
|
+
str
|
126
|
+
end
|
127
|
+
|
128
|
+
def out_at(loc, str)
|
129
|
+
cursor(loc)
|
130
|
+
out str
|
131
|
+
end
|
132
|
+
|
133
|
+
def out_at_with_color(loc, str, fg, bg)
|
134
|
+
return unless str.length > 0
|
135
|
+
cursor loc
|
136
|
+
|
137
|
+
change_fg fg[0]
|
138
|
+
change_bg bg[0]
|
139
|
+
|
140
|
+
current_attrs = [current_fg, current_bg]
|
141
|
+
|
142
|
+
next_output_pos = 0
|
143
|
+
pos = 0
|
144
|
+
|
145
|
+
fg.zip(bg).each do |attrs|
|
146
|
+
if current_attrs!=attrs
|
147
|
+
out str[next_output_pos..pos-1]
|
148
|
+
change_fg attrs[0]
|
149
|
+
change_bg attrs[1]
|
150
|
+
current_attrs = attrs
|
151
|
+
next_output_pos = pos
|
152
|
+
end
|
153
|
+
pos += 1
|
154
|
+
end
|
155
|
+
out str[next_output_pos..-1]
|
156
|
+
end
|
157
|
+
|
158
|
+
def draw_buffer(loc, buffer)
|
159
|
+
loc = loc.clone
|
160
|
+
reset_color
|
161
|
+
buffer.each_line do |line,fg,bg|
|
162
|
+
out_at_with_color loc, line, fg, bg
|
163
|
+
loc.y += 1
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
# convert all \n to \n\r
|
168
|
+
def puts(s=nil)
|
169
|
+
width = xterm_state.size.x
|
170
|
+
lines = "#{s}\n".split("\n").collect do |line|
|
171
|
+
line + " " * (width - (line.length % width))
|
172
|
+
end
|
173
|
+
out lines.flatten.join "\n"
|
174
|
+
end
|
175
|
+
|
176
|
+
def clear; out "\e[2J"; end
|
177
|
+
|
178
|
+
|
179
|
+
# INTERNAL NOTE: xterm returns 3 numbers: ?, height, width
|
180
|
+
# Xterm sends back response as an escape sequence. XtermEventParser knows how to capture and interpret the result.
|
181
|
+
def request_xterm_size; out "\e[18t"; end
|
182
|
+
|
183
|
+
# INTERNAL NOTE: xterm returns 3 numbers: ?, height, width
|
184
|
+
# This returns the entire screen size in pixels - not just the pixel-size of the x-term
|
185
|
+
def request_display_pixel_size; out "\e[14t"; end
|
186
|
+
|
187
|
+
def request_cursor_position; out "\e[?6n"; end
|
188
|
+
|
189
|
+
def request_state_update
|
190
|
+
request_xterm_size
|
191
|
+
request_display_pixel_size
|
192
|
+
end
|
193
|
+
|
194
|
+
def enable_resize_events
|
195
|
+
Signal.trap "SIGWINCH" do
|
196
|
+
request_xterm_size
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def disable_resize_events
|
201
|
+
Signal.trap "SIGWINCH", "DEFAULT"
|
202
|
+
end
|
203
|
+
|
204
|
+
def reset_all
|
205
|
+
disable_focus_events
|
206
|
+
disable_mouse
|
207
|
+
disable_resize_events
|
208
|
+
reset_color
|
209
|
+
show_cursor
|
210
|
+
echo_on
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module WindowBlessing
|
2
|
+
class XtermScreen
|
3
|
+
include GuiGeo
|
4
|
+
include GuiGeo::Tools
|
5
|
+
|
6
|
+
attr_accessor :input, :output, :event_manager, :state, :event_queue
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@event_manager = EventManager.new(self)
|
10
|
+
@state = XtermState.new @event_manager
|
11
|
+
@input = XtermInput.new
|
12
|
+
@output = XtermOutput.new(@state)
|
13
|
+
@running = true
|
14
|
+
@pending_events = []
|
15
|
+
@event_queue = EventQueue.new
|
16
|
+
|
17
|
+
@event_manager.add_handler :key_press do |event|
|
18
|
+
quit if event[:key]==:control_q
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def inspect
|
23
|
+
"<#{self.class}:#{object_id}>"
|
24
|
+
end
|
25
|
+
|
26
|
+
def quit; @running = false; end
|
27
|
+
def running?; @running; end
|
28
|
+
|
29
|
+
def queue_event(e); event_queue << e end
|
30
|
+
def queued_events?; !event_queue.empty? end
|
31
|
+
|
32
|
+
def queue_pending_xterm_events
|
33
|
+
event_queue << input.read_events
|
34
|
+
end
|
35
|
+
|
36
|
+
def wait_for_events(max=100)
|
37
|
+
count = max
|
38
|
+
while !queued_events? && count > 0
|
39
|
+
queue_pending_xterm_events
|
40
|
+
count -= 1
|
41
|
+
sleep 0.01
|
42
|
+
end
|
43
|
+
raise "no events!" unless queued_events?
|
44
|
+
end
|
45
|
+
|
46
|
+
def process_queued_events
|
47
|
+
event_manager.handle_events event_queue.pop_all
|
48
|
+
end
|
49
|
+
|
50
|
+
def process_events
|
51
|
+
queue_pending_xterm_events
|
52
|
+
queue_event :type => :tick
|
53
|
+
process_queued_events
|
54
|
+
end
|
55
|
+
|
56
|
+
def event_loop
|
57
|
+
while running?
|
58
|
+
process_events
|
59
|
+
sleep 1/60.0
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def initialize_screen
|
64
|
+
output.request_state_update
|
65
|
+
wait_for_events
|
66
|
+
process_events
|
67
|
+
end
|
68
|
+
|
69
|
+
# run xterm raw-session
|
70
|
+
# options
|
71
|
+
#
|
72
|
+
def start(options={})
|
73
|
+
in_xterm_state(options) do
|
74
|
+
initialize_screen
|
75
|
+
yield self
|
76
|
+
event_loop
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
# options
|
82
|
+
# :mouse => true
|
83
|
+
# :no_cursor => true
|
84
|
+
# :alternate_screen => true
|
85
|
+
# :full => true (enables all above features)
|
86
|
+
# :utf8
|
87
|
+
def in_xterm_state(options = {})
|
88
|
+
output.echo_off
|
89
|
+
output.enable_alternate_screen if options[:full] || options[:alternate_screen]
|
90
|
+
output.enable_mouse if options[:full] || options[:mouse]
|
91
|
+
output.hide_cursor if options[:full] || options[:no_cursor]
|
92
|
+
output.enable_utf8 if options[:utf8]
|
93
|
+
output.enable_focus_events
|
94
|
+
output.enable_resize_events
|
95
|
+
output.clear
|
96
|
+
|
97
|
+
yield self
|
98
|
+
ensure
|
99
|
+
output.reset_all
|
100
|
+
output.disable_utf8 if options[:utf8]
|
101
|
+
if options[:full] || options[:alternate_screen]
|
102
|
+
output.reset_color
|
103
|
+
output.clear
|
104
|
+
output.disable_alternate_screen
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module WindowBlessing
|
2
|
+
class XtermState
|
3
|
+
attr_accessor :state
|
4
|
+
|
5
|
+
def initialize(event_manager)
|
6
|
+
@state = {:size => point(-1,-1)}
|
7
|
+
|
8
|
+
event_manager.add_handler :xterm_state do |event|
|
9
|
+
state_type = event[:state_type]
|
10
|
+
old_state = state[state_type]
|
11
|
+
new_state = event[:state]
|
12
|
+
state[state_type] = new_state
|
13
|
+
if old_state!=new_state
|
14
|
+
case state_type
|
15
|
+
when :size
|
16
|
+
event_manager.handle_event :type => :resize, :old_size => old_state, :size => new_state, :raw => event[:raw]
|
17
|
+
else
|
18
|
+
event_manager.handle_event :type => :state_change, :state_type => state_type, :old_state => old_state, :state => new_state, :raw => event[:raw]
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def size; state[:size] end
|
26
|
+
end
|
27
|
+
end
|
data/spec/buffer_spec.rb
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module WindowBlessing
|
4
|
+
describe "Buffer" do
|
5
|
+
include Tools
|
6
|
+
|
7
|
+
def test_frame(options={})
|
8
|
+
buffer(point(4,4), {:contents => %w{1234 2345 3456 4567}}.merge(options))
|
9
|
+
end
|
10
|
+
|
11
|
+
it "blank fb" do
|
12
|
+
buffer(point(4,4)).to_s.should == " \n \n \n "
|
13
|
+
end
|
14
|
+
|
15
|
+
it "string init" do
|
16
|
+
buffer(point(4,4),:contents => ["hi","there"]).to_s.should == "hi \nther\n \n "
|
17
|
+
buffer(point(4,4),:contents => "hi\nthere").to_s.should == "hi \nther\n \n "
|
18
|
+
buffer(point(4,4),:contents => "hi\n\t\0here").to_s.should == "hi \n??he\n \n "
|
19
|
+
end
|
20
|
+
|
21
|
+
it "inspect" do
|
22
|
+
buffer(point 4,4).inspect.class.should == String
|
23
|
+
end
|
24
|
+
|
25
|
+
it "invalid init" do
|
26
|
+
expect { buffer(point(4,4),:contents => 1) }.to raise_error
|
27
|
+
end
|
28
|
+
|
29
|
+
it "subbuffer" do
|
30
|
+
test_frame.subbuffer(rect(1,1,2,2)).to_s.should == "34\n45"
|
31
|
+
end
|
32
|
+
|
33
|
+
it "array init" do
|
34
|
+
test_frame.to_s.should == "1234\n2345\n3456\n4567"
|
35
|
+
end
|
36
|
+
|
37
|
+
it "crop" do
|
38
|
+
(f=buffer(point 4,4)).cropped(rect(1,1,2,2)) do
|
39
|
+
f.crop_area.should == rect(1,1,2,2)
|
40
|
+
f.cropped?.should == true
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
it "fill" do
|
45
|
+
fb = buffer(point(4,4))
|
46
|
+
fb.fill :string => "-"
|
47
|
+
fb.to_s.should == "----\n----\n----\n----"
|
48
|
+
end
|
49
|
+
|
50
|
+
it "cropped fill" do
|
51
|
+
(f=test_frame).cropped(rect(1,1,2,1)) do
|
52
|
+
f.fill :string => '-'
|
53
|
+
end.to_s.should == "1234\n2--5\n3456\n4567"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "draw_rect" do
|
57
|
+
(f=buffer(point(4,4))).to_s.should == " \n \n \n "
|
58
|
+
f.draw_rect(rect(1,0,2,2),:string => "-")
|
59
|
+
f.to_s.should == " -- \n -- \n \n "
|
60
|
+
end
|
61
|
+
|
62
|
+
it "clear" do
|
63
|
+
fb = buffer(point 2,2).fill(:string => '-')
|
64
|
+
fb.to_s.should == "--\n--"
|
65
|
+
fb.clear
|
66
|
+
fb.to_s.should == " \n "
|
67
|
+
end
|
68
|
+
|
69
|
+
it "draw_buffer" do
|
70
|
+
f1 = test_frame
|
71
|
+
f2 = buffer(point(2,2), :contents => "ab\nbc")
|
72
|
+
f1.draw_buffer(point(1,1),f2)
|
73
|
+
f1.to_s.should == "1234\n2ab5\n3bc6\n4567"
|
74
|
+
end
|
75
|
+
|
76
|
+
it "cropped draw_buffer" do
|
77
|
+
f1 = test_frame
|
78
|
+
f2 = buffer(point(2,2), :contents => "ab\nbc")
|
79
|
+
f1.cropped(rect(1,1,2,1)) do
|
80
|
+
f1.draw_buffer(point(1,1),f2)
|
81
|
+
end.to_s.should == "1234\n2ab5\n3456\n4567"
|
82
|
+
end
|
83
|
+
|
84
|
+
it "fill only overwrites what is provided" do
|
85
|
+
f0 = test_frame :bg => 9, :fg => 8
|
86
|
+
|
87
|
+
f1 = f0.clone
|
88
|
+
f1.to_s.should == "1234\n2345\n3456\n4567"
|
89
|
+
f1.fg_buffer.should == [[8, 8, 8, 8], [8, 8, 8, 8], [8, 8, 8, 8], [8, 8, 8, 8]]
|
90
|
+
f1.bg_buffer.should == [[9, 9, 9, 9], [9, 9, 9, 9], [9, 9, 9, 9], [9, 9, 9, 9]]
|
91
|
+
|
92
|
+
f1.fill :string => "!"
|
93
|
+
f1.to_s.should == "!!!!\n!!!!\n!!!!\n!!!!"
|
94
|
+
f1.fg_buffer.should == [[8, 8, 8, 8], [8, 8, 8, 8], [8, 8, 8, 8], [8, 8, 8, 8]]
|
95
|
+
f1.bg_buffer.should == [[9, 9, 9, 9], [9, 9, 9, 9], [9, 9, 9, 9], [9, 9, 9, 9]]
|
96
|
+
|
97
|
+
f1 = f0.clone
|
98
|
+
f1.fill :bg => 0
|
99
|
+
f1.to_s.should == "1234\n2345\n3456\n4567"
|
100
|
+
f1.fg_buffer.should == [[8, 8, 8, 8], [8, 8, 8, 8], [8, 8, 8, 8], [8, 8, 8, 8]]
|
101
|
+
f1.bg_buffer.should == [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
|
102
|
+
|
103
|
+
f1 = f0.clone
|
104
|
+
f1.fill :fg => 0
|
105
|
+
f1.to_s.should == "1234\n2345\n3456\n4567"
|
106
|
+
f1.fg_buffer.should == [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
|
107
|
+
f1.bg_buffer.should == [[9, 9, 9, 9], [9, 9, 9, 9], [9, 9, 9, 9], [9, 9, 9, 9]]
|
108
|
+
end
|
109
|
+
|
110
|
+
it "cropped fill only overwrites what is provided" do
|
111
|
+
f0 = test_frame :bg => 9, :fg => 8
|
112
|
+
|
113
|
+
f1 = f0.clone
|
114
|
+
f1.to_s.should == "1234\n2345\n3456\n4567"
|
115
|
+
f1.fg_buffer.should == [[8, 8, 8, 8], [8, 8, 8, 8], [8, 8, 8, 8], [8, 8, 8, 8]]
|
116
|
+
f1.bg_buffer.should == [[9, 9, 9, 9], [9, 9, 9, 9], [9, 9, 9, 9], [9, 9, 9, 9]]
|
117
|
+
|
118
|
+
f1.cropped(rect(1,1,2,2)) {f1.fill :string => "!"}
|
119
|
+
f1.to_s.should == "1234\n2!!5\n3!!6\n4567"
|
120
|
+
f1.fg_buffer.should == [[8, 8, 8, 8], [8, 8, 8, 8], [8, 8, 8, 8], [8, 8, 8, 8]]
|
121
|
+
f1.bg_buffer.should == [[9, 9, 9, 9], [9, 9, 9, 9], [9, 9, 9, 9], [9, 9, 9, 9]]
|
122
|
+
|
123
|
+
f1 = f0.clone
|
124
|
+
f1.cropped(rect(1,1,2,2)) {f1.fill :bg => 0}
|
125
|
+
f1.to_s.should == "1234\n2345\n3456\n4567"
|
126
|
+
f1.fg_buffer.should == [[8, 8, 8, 8], [8, 8, 8, 8], [8, 8, 8, 8], [8, 8, 8, 8]]
|
127
|
+
f1.bg_buffer.should == [[9, 9, 9, 9], [9, 0, 0, 9], [9, 0, 0, 9], [9, 9, 9, 9]]
|
128
|
+
|
129
|
+
f1 = f0.clone
|
130
|
+
f1.cropped(rect(1,1,2,2)) {f1.fill :fg => 0}
|
131
|
+
f1.to_s.should == "1234\n2345\n3456\n4567"
|
132
|
+
f1.fg_buffer.should == [[8, 8, 8, 8], [8, 0, 0, 8], [8, 0, 0, 8], [8, 8, 8, 8]]
|
133
|
+
f1.bg_buffer.should == [[9, 9, 9, 9], [9, 9, 9, 9], [9, 9, 9, 9], [9, 9, 9, 9]]
|
134
|
+
end
|
135
|
+
|
136
|
+
it "dirty" do
|
137
|
+
f1 = test_frame
|
138
|
+
f1.dirty?.should == false
|
139
|
+
f1.dirty rect(1,2,3,4)
|
140
|
+
f1.dirty?.should == true
|
141
|
+
|
142
|
+
f1.dirty_area.should == rect(1,2,3,2)
|
143
|
+
|
144
|
+
s = f1.dirty_subbuffer
|
145
|
+
s.to_s.should == "456\n567"
|
146
|
+
|
147
|
+
f1.clean
|
148
|
+
f1.dirty?.should == false
|
149
|
+
end
|
150
|
+
|
151
|
+
it "on_dirty" do
|
152
|
+
f1 = test_frame
|
153
|
+
|
154
|
+
is_now_dirty = false
|
155
|
+
f1.on_dirty do
|
156
|
+
is_now_dirty = true
|
157
|
+
end
|
158
|
+
is_now_dirty.should == false
|
159
|
+
f1.dirty
|
160
|
+
is_now_dirty.should == true
|
161
|
+
end
|
162
|
+
|
163
|
+
it "color buffers" do
|
164
|
+
f1 = test_frame
|
165
|
+
|
166
|
+
f1.fg_buffer.should == [[7, 7, 7, 7], [7, 7, 7, 7], [7, 7, 7, 7], [7, 7, 7, 7]]
|
167
|
+
f1.bg_buffer.should == [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|