whirled_peas 0.4.1 → 0.5.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +111 -73
- data/Rakefile +37 -3
- data/bin/debug +35 -0
- data/lib/whirled_peas.rb +9 -7
- data/lib/whirled_peas/command_line.rb +25 -32
- data/lib/whirled_peas/debugger.rb +80 -0
- data/lib/whirled_peas/errors.rb +2 -0
- data/lib/whirled_peas/frame.rb +0 -1
- data/lib/whirled_peas/frame/consumer.rb +30 -0
- data/lib/whirled_peas/frame/debug_consumer.rb +30 -0
- data/lib/whirled_peas/frame/event_loop.rb +29 -30
- data/lib/whirled_peas/frame/producer.rb +11 -5
- data/lib/whirled_peas/graphics.rb +5 -0
- data/lib/whirled_peas/graphics/box_painter.rb +100 -0
- data/lib/whirled_peas/graphics/canvas.rb +107 -0
- data/lib/whirled_peas/graphics/container_coords.rb +61 -0
- data/lib/whirled_peas/graphics/container_dimensions.rb +65 -0
- data/lib/whirled_peas/graphics/container_painter.rb +116 -0
- data/lib/whirled_peas/graphics/debugger.rb +43 -0
- data/lib/whirled_peas/graphics/grid_painter.rb +56 -0
- data/lib/whirled_peas/graphics/mock_screen.rb +26 -0
- data/lib/whirled_peas/graphics/painter.rb +24 -0
- data/lib/whirled_peas/graphics/renderer.rb +49 -0
- data/lib/whirled_peas/graphics/screen.rb +65 -0
- data/lib/whirled_peas/graphics/text_dimensions.rb +15 -0
- data/lib/whirled_peas/graphics/text_painter.rb +38 -0
- data/lib/whirled_peas/settings.rb +5 -0
- data/lib/whirled_peas/settings/bg_color.rb +22 -0
- data/lib/whirled_peas/settings/border.rb +101 -0
- data/lib/whirled_peas/settings/box_settings.rb +8 -0
- data/lib/whirled_peas/{utils → settings}/color.rb +3 -35
- data/lib/whirled_peas/settings/container_settings.rb +128 -0
- data/lib/whirled_peas/settings/debugger.rb +87 -0
- data/lib/whirled_peas/settings/display_flow.rb +25 -0
- data/lib/whirled_peas/settings/element_settings.rb +61 -0
- data/lib/whirled_peas/settings/grid_settings.rb +11 -0
- data/lib/whirled_peas/settings/margin.rb +8 -0
- data/lib/whirled_peas/settings/padding.rb +8 -0
- data/lib/whirled_peas/settings/position.rb +15 -0
- data/lib/whirled_peas/settings/spacing.rb +24 -0
- data/lib/whirled_peas/settings/text_align.rb +19 -0
- data/lib/whirled_peas/settings/text_color.rb +19 -0
- data/lib/whirled_peas/settings/text_settings.rb +15 -0
- data/lib/whirled_peas/template/box_element.rb +8 -0
- data/lib/whirled_peas/template/composer.rb +68 -0
- data/lib/whirled_peas/template/container.rb +28 -0
- data/lib/whirled_peas/template/debugger.rb +34 -0
- data/lib/whirled_peas/template/element.rb +1 -218
- data/lib/whirled_peas/template/grid_element.rb +8 -0
- data/lib/whirled_peas/template/text_element.rb +24 -0
- data/lib/whirled_peas/utils/ansi.rb +6 -56
- data/lib/whirled_peas/utils/formatted_string.rb +64 -0
- data/lib/whirled_peas/version.rb +1 -1
- data/screen_test/rendered/elements/box.frame +1 -0
- data/screen_test/rendered/elements/box.rb +20 -0
- data/screen_test/rendered/elements/grid.frame +1 -0
- data/screen_test/rendered/elements/grid.rb +13 -0
- data/screen_test/rendered/elements/screen_overflow.rb +9 -0
- data/screen_test/rendered/elements/text.frame +1 -0
- data/screen_test/rendered/elements/text.rb +9 -0
- data/screen_test/rendered/elements/text_multiline.frame +1 -0
- data/screen_test/rendered/elements/text_multiline.rb +9 -0
- data/screen_test/rendered/settings/align/box.frame +1 -0
- data/screen_test/rendered/settings/align/box.rb +20 -0
- data/screen_test/rendered/settings/align/children_center.frame +1 -0
- data/screen_test/rendered/settings/align/children_center.rb +13 -0
- data/screen_test/rendered/settings/align/children_left.frame +1 -0
- data/screen_test/rendered/settings/align/children_left.rb +13 -0
- data/screen_test/rendered/settings/align/children_right.frame +1 -0
- data/screen_test/rendered/settings/align/children_right.rb +13 -0
- data/screen_test/rendered/settings/align/grid.frame +1 -0
- data/screen_test/rendered/settings/align/grid.rb +20 -0
- data/screen_test/rendered/settings/ansi/bold.frame +1 -0
- data/screen_test/rendered/settings/ansi/bold.rb +15 -0
- data/screen_test/rendered/settings/ansi/color.frame +1 -0
- data/screen_test/rendered/settings/ansi/color.rb +37 -0
- data/screen_test/rendered/settings/ansi/underline.frame +1 -0
- data/screen_test/rendered/settings/ansi/underline.rb +15 -0
- data/screen_test/rendered/settings/border.frame +1 -0
- data/screen_test/rendered/settings/border.rb +13 -0
- data/screen_test/rendered/settings/flow/l2r.frame +1 -0
- data/screen_test/rendered/settings/flow/l2r.rb +24 -0
- data/screen_test/rendered/settings/flow/t2b.frame +1 -0
- data/screen_test/rendered/settings/flow/t2b.rb +24 -0
- data/screen_test/rendered/settings/height/box.frame +1 -0
- data/screen_test/rendered/settings/height/box.rb +13 -0
- data/screen_test/rendered/settings/height/grid.frame +1 -0
- data/screen_test/rendered/settings/height/grid.rb +14 -0
- data/screen_test/rendered/settings/height/overflow_box.frame +1 -0
- data/screen_test/rendered/settings/height/overflow_box.rb +13 -0
- data/screen_test/rendered/settings/height/overflow_box_l2r.frame +1 -0
- data/screen_test/rendered/settings/height/overflow_box_l2r.rb +15 -0
- data/screen_test/rendered/settings/height/overflow_box_t2b.frame +1 -0
- data/screen_test/rendered/settings/height/overflow_box_t2b.rb +14 -0
- data/screen_test/rendered/settings/height/overflow_grid.frame +1 -0
- data/screen_test/rendered/settings/height/overflow_grid.rb +16 -0
- data/screen_test/rendered/settings/margin.frame +1 -0
- data/screen_test/rendered/settings/margin.rb +14 -0
- data/screen_test/rendered/settings/padding.frame +1 -0
- data/screen_test/rendered/settings/padding.rb +11 -0
- data/screen_test/rendered/settings/position/box_left.frame +1 -0
- data/screen_test/rendered/settings/position/box_left.rb +17 -0
- data/screen_test/rendered/settings/position/box_left_negative.frame +1 -0
- data/screen_test/rendered/settings/position/box_left_negative.rb +17 -0
- data/screen_test/rendered/settings/position/box_top.frame +1 -0
- data/screen_test/rendered/settings/position/box_top.rb +17 -0
- data/screen_test/rendered/settings/position/box_top_negative.frame +1 -0
- data/screen_test/rendered/settings/position/box_top_negative.rb +17 -0
- data/screen_test/rendered/settings/position/grid_left.frame +1 -0
- data/screen_test/rendered/settings/position/grid_left.rb +18 -0
- data/screen_test/rendered/settings/position/grid_left_negative.frame +1 -0
- data/screen_test/rendered/settings/position/grid_left_negative.rb +18 -0
- data/screen_test/rendered/settings/position/grid_top.frame +1 -0
- data/screen_test/rendered/settings/position/grid_top.rb +18 -0
- data/screen_test/rendered/settings/position/grid_top_negative.frame +1 -0
- data/screen_test/rendered/settings/position/grid_top_negative.rb +18 -0
- data/screen_test/rendered/settings/title_font.frame +1 -0
- data/screen_test/rendered/settings/title_font.rb +12 -0
- data/screen_test/rendered/settings/width/box.frame +1 -0
- data/screen_test/rendered/settings/width/box.rb +13 -0
- data/screen_test/rendered/settings/width/grid.frame +1 -0
- data/screen_test/rendered/settings/width/grid.rb +14 -0
- data/screen_test/rendered/settings/width/overflow_box.frame +1 -0
- data/screen_test/rendered/settings/width/overflow_box.rb +11 -0
- data/screen_test/rendered/settings/width/overflow_box_l2r.frame +1 -0
- data/screen_test/rendered/settings/width/overflow_box_l2r.rb +14 -0
- data/screen_test/rendered/settings/width/overflow_box_t2b.frame +1 -0
- data/screen_test/rendered/settings/width/overflow_box_t2b.rb +15 -0
- data/screen_test/rendered/settings/width/overflow_grid.frame +1 -0
- data/screen_test/rendered/settings/width/overflow_grid.rb +14 -0
- data/screen_test/screen_tester.rb +191 -0
- metadata +122 -10
- data/bin/title_fonts +0 -6
- data/lib/whirled_peas/frame/print_consumer.rb +0 -33
- data/lib/whirled_peas/template/settings.rb +0 -530
- data/lib/whirled_peas/ui.rb +0 -5
- data/lib/whirled_peas/ui/canvas.rb +0 -68
- data/lib/whirled_peas/ui/painter.rb +0 -287
- data/lib/whirled_peas/ui/screen.rb +0 -63
@@ -1,7 +1,15 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
require 'whirled_peas/graphics/debugger'
|
4
|
+
require 'whirled_peas/graphics/renderer'
|
5
|
+
require 'whirled_peas/graphics/screen'
|
6
|
+
require 'whirled_peas/frame/debug_consumer'
|
7
|
+
require 'whirled_peas/frame/event_loop'
|
8
|
+
require 'whirled_peas/frame/producer'
|
9
|
+
require 'whirled_peas/template/debugger'
|
10
|
+
|
1
11
|
module WhirledPeas
|
2
12
|
class Command
|
3
|
-
DEFAULT_REFRESH_RATE = 30
|
4
|
-
|
5
13
|
DEFAULT_LOG_LEVEL = Logger::INFO
|
6
14
|
DEFAULT_FORMATTER = proc do |severity, datetime, progname, msg|
|
7
15
|
if msg.is_a?(Exception)
|
@@ -95,16 +103,13 @@ module WhirledPeas
|
|
95
103
|
|
96
104
|
def start
|
97
105
|
super
|
98
|
-
require 'whirled_peas/frame/event_loop'
|
99
|
-
require 'whirled_peas/frame/producer'
|
100
106
|
|
101
107
|
logger = self.class.build_logger(File.open('whirled_peas.log', 'a'))
|
102
108
|
|
103
109
|
consumer = Frame::EventLoop.new(
|
104
110
|
WhirledPeas.config.template_factory,
|
105
111
|
WhirledPeas.config.loading_template_factory,
|
106
|
-
|
107
|
-
logger
|
112
|
+
logger: logger
|
108
113
|
)
|
109
114
|
Frame::Producer.produce(consumer, logger) do |producer|
|
110
115
|
begin
|
@@ -121,18 +126,9 @@ module WhirledPeas
|
|
121
126
|
class ListFramesCommand < ConfigCommand
|
122
127
|
def start
|
123
128
|
super
|
124
|
-
require 'whirled_peas/frame/print_consumer'
|
125
|
-
require 'whirled_peas/frame/producer'
|
126
129
|
|
127
|
-
|
128
|
-
|
129
|
-
begin
|
130
|
-
WhirledPeas.config.driver.start(producer)
|
131
|
-
rescue => e
|
132
|
-
logger.warn(LOGGER_ID) { 'Driver exited with error, terminating producer...' }
|
133
|
-
logger.error(LOGGER_ID) { e }
|
134
|
-
raise
|
135
|
-
end
|
130
|
+
Frame::Producer.produce(Frame::DebugConsumer.new) do |producer|
|
131
|
+
WhirledPeas.config.driver.start(producer)
|
136
132
|
end
|
137
133
|
end
|
138
134
|
end
|
@@ -141,24 +137,25 @@ module WhirledPeas
|
|
141
137
|
def start
|
142
138
|
super
|
143
139
|
|
144
|
-
if args.last == '--
|
145
|
-
|
140
|
+
if args.last == '--template'
|
141
|
+
element = WhirledPeas.config.template_factory.build(frame, frame_args)
|
142
|
+
puts Template::Debugger.new(element).debug
|
143
|
+
exit
|
144
|
+
elsif args.last == '--painter'
|
145
|
+
element = WhirledPeas.config.template_factory.build(frame, frame_args)
|
146
|
+
painter = Graphics::Renderer.new(element, *Graphics::Screen.current_dimensions).painter
|
147
|
+
puts Graphics::Debugger.new(painter).debug
|
146
148
|
exit
|
147
149
|
end
|
148
150
|
|
149
|
-
require 'whirled_peas/frame/event_loop'
|
150
|
-
require 'whirled_peas/frame/producer'
|
151
|
-
|
152
151
|
logger = self.class.build_logger(File.open('whirled_peas.log', 'a'))
|
153
152
|
|
154
153
|
consumer = Frame::EventLoop.new(
|
155
154
|
WhirledPeas.config.template_factory,
|
156
|
-
|
157
|
-
DEFAULT_REFRESH_RATE,
|
158
|
-
logger
|
155
|
+
logger: logger
|
159
156
|
)
|
160
157
|
Frame::Producer.produce(consumer, logger) do |producer|
|
161
|
-
producer.send_frame(
|
158
|
+
producer.send_frame(frame, args: frame_args)
|
162
159
|
end
|
163
160
|
end
|
164
161
|
|
@@ -173,9 +170,9 @@ module WhirledPeas
|
|
173
170
|
elsif args.length < 2
|
174
171
|
@error_text = "#{self.class.command_name} requires a frame name"
|
175
172
|
else
|
176
|
-
require 'json'
|
177
173
|
@frame = args[1]
|
178
174
|
@frame_args = {}
|
175
|
+
return if args.length < 3 || args[2][0..1] == '--'
|
179
176
|
JSON.parse(args[2] || '{}').each do |key, value|
|
180
177
|
@frame_args[key.to_sym] = value
|
181
178
|
end
|
@@ -200,15 +197,11 @@ module WhirledPeas
|
|
200
197
|
exit
|
201
198
|
end
|
202
199
|
|
203
|
-
require 'whirled_peas/frame/event_loop'
|
204
|
-
require 'whirled_peas/frame/producer'
|
205
|
-
|
206
200
|
logger = self.class.build_logger(File.open('whirled_peas.log', 'a'))
|
207
201
|
consumer = Frame::EventLoop.new(
|
208
202
|
WhirledPeas.config.template_factory,
|
209
203
|
WhirledPeas.config.loading_template_factory,
|
210
|
-
|
211
|
-
logger
|
204
|
+
logger: logger
|
212
205
|
)
|
213
206
|
Frame::Producer.produce(consumer, logger) { sleep(5) }
|
214
207
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'whirled_peas/frame/event_loop'
|
2
|
+
require 'whirled_peas/frame/producer'
|
3
|
+
require 'whirled_peas/graphics/debugger'
|
4
|
+
require 'whirled_peas/graphics/mock_screen'
|
5
|
+
require 'whirled_peas/graphics/renderer'
|
6
|
+
require 'whirled_peas/graphics/screen'
|
7
|
+
require 'whirled_peas/template/debugger'
|
8
|
+
|
9
|
+
module WhirledPeas
|
10
|
+
class Debugger
|
11
|
+
module Option
|
12
|
+
DISABLE_SCREEN = :disable_screen
|
13
|
+
PAINTER = :painter
|
14
|
+
TEMPLATE = :template
|
15
|
+
|
16
|
+
VALID = [DISABLE_SCREEN, PAINTER, TEMPLATE]
|
17
|
+
end
|
18
|
+
private_constant :Option
|
19
|
+
|
20
|
+
FRAME = 'debug'
|
21
|
+
private_constant :FRAME
|
22
|
+
|
23
|
+
def initialize(template_file, option=nil)
|
24
|
+
unless option.nil? || Option::VALID.include?(option)
|
25
|
+
message =
|
26
|
+
"Invalid option: #{option}, expecting one of #{Option::VALID.join(', ')}"
|
27
|
+
raise ArgumentError, message
|
28
|
+
end
|
29
|
+
@template_file = template_file
|
30
|
+
@option = option
|
31
|
+
end
|
32
|
+
|
33
|
+
def debug
|
34
|
+
require template_file
|
35
|
+
template_factory = TemplateFactory.new
|
36
|
+
if play_frame?
|
37
|
+
screen = if disable_screen?
|
38
|
+
Graphics::MockScreen.new(80, 40)
|
39
|
+
else
|
40
|
+
Graphics::Screen.new
|
41
|
+
end
|
42
|
+
consumer = Frame::EventLoop.new(template_factory, screen: screen)
|
43
|
+
Frame::Producer.produce(consumer) do |producer|
|
44
|
+
producer.send_frame(FRAME, args: {})
|
45
|
+
end
|
46
|
+
return
|
47
|
+
end
|
48
|
+
|
49
|
+
template = template_factory.build(FRAME, {})
|
50
|
+
if print_painter?
|
51
|
+
painter = Graphics::Renderer.new(template, *Graphics::Screen.current_dimensions).painter
|
52
|
+
puts Graphics::Debugger.new(painter).debug
|
53
|
+
elsif print_template?
|
54
|
+
puts Template::Debugger.new(template).debug
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
attr_reader :template_file, :option
|
61
|
+
|
62
|
+
def play_frame?
|
63
|
+
option.nil? || option == Option::DISABLE_SCREEN
|
64
|
+
end
|
65
|
+
|
66
|
+
def disable_screen?
|
67
|
+
!option.nil? && option == Option::DISABLE_SCREEN
|
68
|
+
end
|
69
|
+
|
70
|
+
def print_painter?
|
71
|
+
!option.nil? && option == Option::PAINTER
|
72
|
+
end
|
73
|
+
|
74
|
+
def print_template?
|
75
|
+
!option.nil? && option == Option::TEMPLATE
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
private_constant :Debugger
|
80
|
+
end
|
data/lib/whirled_peas/errors.rb
CHANGED
data/lib/whirled_peas/frame.rb
CHANGED
@@ -0,0 +1,30 @@
|
|
1
|
+
module WhirledPeas
|
2
|
+
module Frame
|
3
|
+
# Abstract class for consuming frame events.
|
4
|
+
class Consumer
|
5
|
+
EOF = '__EOF__'
|
6
|
+
|
7
|
+
def enqueue(name, duration, args)
|
8
|
+
raise NotImplemented, "#{self.class} must implement #enqueue"
|
9
|
+
end
|
10
|
+
|
11
|
+
def running?
|
12
|
+
@running == true
|
13
|
+
end
|
14
|
+
|
15
|
+
def start
|
16
|
+
self.running = true
|
17
|
+
end
|
18
|
+
|
19
|
+
def stop
|
20
|
+
enqueue(EOF, nil, {})
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
attr_writer :running
|
26
|
+
end
|
27
|
+
|
28
|
+
private_constant :Consumer
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'whirled_peas/null_logger'
|
2
|
+
|
3
|
+
require_relative 'consumer'
|
4
|
+
|
5
|
+
module WhirledPeas
|
6
|
+
module Frame
|
7
|
+
class DebugConsumer < Consumer
|
8
|
+
LOGGER_ID = 'PRINTER'
|
9
|
+
|
10
|
+
def initialize(output=STDOUT, logger=NullLogger.new)
|
11
|
+
@output = output
|
12
|
+
@logger = logger
|
13
|
+
end
|
14
|
+
|
15
|
+
def enqueue(name, duration, args)
|
16
|
+
if name == EOF
|
17
|
+
output.puts "EOF frame detected"
|
18
|
+
else
|
19
|
+
displayed_for = duration ? "#{duration} second(s)" : '1 frame'
|
20
|
+
args_str = args.empty? ? '' : " '#{JSON.generate(args)}'"
|
21
|
+
output.puts "Frame '#{name}' displayed for #{displayed_for}#{args_str}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
attr_reader :output, :logger
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -1,17 +1,28 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require 'whirled_peas/null_logger'
|
2
|
+
require 'whirled_peas/graphics/screen'
|
3
|
+
|
4
|
+
require_relative 'consumer'
|
3
5
|
|
4
6
|
module WhirledPeas
|
5
7
|
module Frame
|
6
|
-
class EventLoop
|
8
|
+
class EventLoop < Consumer
|
9
|
+
DEFAULT_REFRESH_RATE = 30
|
10
|
+
|
7
11
|
LOGGER_ID = 'EVENT LOOP'
|
8
12
|
|
9
|
-
def initialize(
|
13
|
+
def initialize(
|
14
|
+
template_factory,
|
15
|
+
loading_template_factory=nil,
|
16
|
+
refresh_rate: DEFAULT_REFRESH_RATE,
|
17
|
+
logger: NullLogger.new,
|
18
|
+
screen: Graphics::Screen.new
|
19
|
+
)
|
10
20
|
@template_factory = template_factory
|
11
21
|
@loading_template_factory = loading_template_factory
|
12
22
|
@queue = Queue.new
|
13
23
|
@frame_duration = 1.0 / refresh_rate
|
14
24
|
@logger = logger
|
25
|
+
@screen = screen
|
15
26
|
end
|
16
27
|
|
17
28
|
def enqueue(name, duration, args)
|
@@ -19,50 +30,38 @@ module WhirledPeas
|
|
19
30
|
queue.push([name, duration || frame_duration, args])
|
20
31
|
end
|
21
32
|
|
22
|
-
def
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
def start(screen=UI::Screen.new)
|
27
|
-
wait_for_content(screen)
|
28
|
-
play_content(screen)
|
33
|
+
def start
|
34
|
+
super
|
35
|
+
wait_for_content
|
36
|
+
play_content
|
29
37
|
rescue
|
38
|
+
self.running = false
|
30
39
|
logger.warn(LOGGER_ID) { 'Exiting with error' }
|
31
40
|
raise
|
32
41
|
ensure
|
33
|
-
|
34
|
-
# instance reflects actual state.
|
35
|
-
@running = false
|
36
|
-
screen.finalize if screen
|
37
|
-
end
|
38
|
-
|
39
|
-
def stop
|
40
|
-
logger.info(LOGGER_ID) { 'Stopping...' }
|
41
|
-
enqueue(Frame::EOF, nil, {})
|
42
|
-
@running = false
|
42
|
+
screen.finalize
|
43
43
|
end
|
44
44
|
|
45
45
|
private
|
46
46
|
|
47
|
-
attr_reader :template_factory, :loading_template_factory, :queue, :frame_duration, :logger
|
47
|
+
attr_reader :template_factory, :loading_template_factory, :queue, :frame_duration, :logger, :screen
|
48
48
|
|
49
|
-
def wait_for_content
|
49
|
+
def wait_for_content
|
50
50
|
if loading_template_factory
|
51
|
-
play_loading_screen
|
51
|
+
play_loading_screen
|
52
52
|
else
|
53
53
|
sleep(frame_duration) while queue.empty?
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
-
def play_loading_screen
|
57
|
+
def play_loading_screen
|
58
58
|
while queue.empty?
|
59
59
|
screen.paint(loading_template_factory.build)
|
60
60
|
sleep(frame_duration)
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
64
|
-
def play_content
|
65
|
-
@running = true
|
64
|
+
def play_content
|
66
65
|
template = nil
|
67
66
|
frame_until = Time.new(0) # Tell the loop to immediately pick up a new frame
|
68
67
|
while running?
|
@@ -73,15 +72,15 @@ module WhirledPeas
|
|
73
72
|
screen.refresh
|
74
73
|
elsif !queue.empty?
|
75
74
|
name, duration, args = queue.pop
|
76
|
-
if name ==
|
77
|
-
|
75
|
+
if name == EOF
|
76
|
+
self.running = false
|
78
77
|
else
|
79
78
|
frame_until = frame_start + duration
|
80
79
|
template = template_factory.build(name, args)
|
81
80
|
screen.paint(template)
|
82
81
|
end
|
83
82
|
else
|
84
|
-
wait_for_content
|
83
|
+
wait_for_content
|
85
84
|
end
|
86
85
|
sleep([0, next_frame_at - Time.now].max)
|
87
86
|
end
|
@@ -1,15 +1,22 @@
|
|
1
1
|
require 'socket'
|
2
2
|
require 'json'
|
3
3
|
|
4
|
-
|
4
|
+
require 'whirled_peas/null_logger'
|
5
5
|
|
6
6
|
module WhirledPeas
|
7
7
|
module Frame
|
8
|
+
# A Producer is the object given to the driver as the interface that allows
|
9
|
+
# the driver to emit frame events. The recommended way of creating a Producer
|
10
|
+
# is by invoking `Producer.produce` as it handles the lifecycle methods of
|
11
|
+
# the consumer.
|
8
12
|
class Producer
|
9
13
|
LOGGER_ID = 'PRODUCER'
|
10
14
|
|
11
|
-
# Manages the
|
12
|
-
#
|
15
|
+
# Manages the consumer lifecycle and yields a Producer to send frames to the
|
16
|
+
# consumer
|
17
|
+
#
|
18
|
+
# @param consumer [Consumer] instance that consumes frame events through
|
19
|
+
# `#enqueue`
|
13
20
|
def self.produce(consumer, logger=NullLogger.new)
|
14
21
|
producer = new(consumer, logger)
|
15
22
|
consumer_thread = Thread.new do
|
@@ -17,14 +24,13 @@ module WhirledPeas
|
|
17
24
|
consumer.start
|
18
25
|
end
|
19
26
|
yield producer
|
20
|
-
producer.send_frame(Frame::EOF)
|
21
27
|
producer.flush
|
22
28
|
rescue => e
|
23
|
-
consumer.stop if consumer
|
24
29
|
logger.warn(LOGGER_ID) { 'Exited with error' }
|
25
30
|
logger.error(LOGGER_ID) { e }
|
26
31
|
raise
|
27
32
|
ensure
|
33
|
+
consumer.stop
|
28
34
|
consumer_thread.join if consumer_thread
|
29
35
|
end
|
30
36
|
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require_relative 'container_painter'
|
2
|
+
require_relative 'container_dimensions'
|
3
|
+
|
4
|
+
module WhirledPeas
|
5
|
+
module Graphics
|
6
|
+
class BoxPainter < ContainerPainter
|
7
|
+
def paint(canvas, &block)
|
8
|
+
super
|
9
|
+
return unless canvas.writable?
|
10
|
+
if element.settings.horizontal_flow?
|
11
|
+
paint_horizontally(canvas, &block)
|
12
|
+
else
|
13
|
+
paint_vertically(canvas, &block)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def dimensions
|
18
|
+
@dimensions ||= begin
|
19
|
+
content_width = 0
|
20
|
+
content_height = 0
|
21
|
+
if settings.horizontal_flow?
|
22
|
+
each_child do |child|
|
23
|
+
content_width += child.dimensions.outer_width
|
24
|
+
if child.dimensions.outer_height > content_height
|
25
|
+
content_height = child.dimensions.outer_height
|
26
|
+
end
|
27
|
+
end
|
28
|
+
else
|
29
|
+
each_child do |child|
|
30
|
+
if child.dimensions.outer_width > content_width
|
31
|
+
content_width = child.dimensions.outer_width
|
32
|
+
end
|
33
|
+
content_height += child.dimensions.outer_height
|
34
|
+
end
|
35
|
+
end
|
36
|
+
ContainerDimensions.new(settings, content_width, content_height)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def paint_horizontally(canvas, &block)
|
43
|
+
stroke_top = coords(canvas).content_top
|
44
|
+
stroke_left = coords(canvas).content_left
|
45
|
+
total_child_width = 0
|
46
|
+
each_child { |c| total_child_width += c.dimensions.outer_width }
|
47
|
+
if settings.align_center?
|
48
|
+
stroke_left += (dimensions.content_width - total_child_width) / 2
|
49
|
+
elsif settings.align_right?
|
50
|
+
stroke_left += dimensions.content_width - total_child_width
|
51
|
+
end
|
52
|
+
given_width = 0
|
53
|
+
each_child do |child|
|
54
|
+
child_width = [
|
55
|
+
child.dimensions.outer_width,
|
56
|
+
dimensions.content_width - given_width
|
57
|
+
].min
|
58
|
+
child_canvas = canvas.child(
|
59
|
+
stroke_left + given_width,
|
60
|
+
stroke_top,
|
61
|
+
child_width,
|
62
|
+
[dimensions.content_height, child.dimensions.outer_height].min
|
63
|
+
)
|
64
|
+
child.paint(child_canvas, &block)
|
65
|
+
given_width += child_width
|
66
|
+
break if given_width == dimensions.content_width
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def paint_vertically(canvas, &block)
|
71
|
+
stroke_top = coords(canvas).content_top
|
72
|
+
stroke_left = coords(canvas).content_left
|
73
|
+
given_height = 0
|
74
|
+
each_child do |child|
|
75
|
+
if settings.align_center?
|
76
|
+
justify_offset = (dimensions.content_width - child.dimensions.outer_width) / 2
|
77
|
+
elsif settings.align_right?
|
78
|
+
justify_offset = dimensions.content_width - child.dimensions.outer_width
|
79
|
+
else
|
80
|
+
justify_offset = 0
|
81
|
+
end
|
82
|
+
child_height = [
|
83
|
+
child.dimensions.outer_height,
|
84
|
+
dimensions.content_height - given_height
|
85
|
+
].min
|
86
|
+
child_canvas = canvas.child(
|
87
|
+
stroke_left + justify_offset,
|
88
|
+
stroke_top + given_height,
|
89
|
+
[dimensions.content_width, child.dimensions.outer_width].min,
|
90
|
+
child_height
|
91
|
+
)
|
92
|
+
child.paint(child_canvas, &block)
|
93
|
+
given_height += child_height
|
94
|
+
break if given_height == dimensions.content_height
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
private_constant :BoxPainter
|
99
|
+
end
|
100
|
+
end
|