cyberarm_engine 0.24.3 → 0.24.5

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.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +8 -8
  3. data/.rubocop.yml +7 -7
  4. data/.travis.yml +5 -5
  5. data/Gemfile +6 -6
  6. data/Gemfile.lock +24 -0
  7. data/LICENSE.txt +21 -21
  8. data/README.md +74 -74
  9. data/Rakefile +10 -10
  10. data/assets/shaders/fragment/g_buffer.glsl +30 -30
  11. data/assets/shaders/fragment/lighting.glsl +115 -69
  12. data/assets/shaders/include/light_struct.glsl +11 -11
  13. data/assets/shaders/include/material_struct.glsl +16 -16
  14. data/assets/shaders/vertex/g_buffer.glsl +28 -28
  15. data/assets/shaders/vertex/lighting.glsl +24 -24
  16. data/bin/console +14 -14
  17. data/bin/setup +8 -8
  18. data/cyberarm_engine.gemspec +36 -36
  19. data/lib/cyberarm_engine/animator.rb +219 -219
  20. data/lib/cyberarm_engine/background.rb +180 -179
  21. data/lib/cyberarm_engine/background_image.rb +93 -93
  22. data/lib/cyberarm_engine/background_nine_slice.rb +142 -142
  23. data/lib/cyberarm_engine/bounding_box.rb +150 -150
  24. data/lib/cyberarm_engine/builtin/intro_state.rb +130 -130
  25. data/lib/cyberarm_engine/cache/download_manager.rb +123 -123
  26. data/lib/cyberarm_engine/cache.rb +4 -4
  27. data/lib/cyberarm_engine/common.rb +128 -128
  28. data/lib/cyberarm_engine/config_file.rb +46 -46
  29. data/lib/cyberarm_engine/console/command.rb +157 -157
  30. data/lib/cyberarm_engine/console/commands/help_command.rb +43 -43
  31. data/lib/cyberarm_engine/console/subcommand.rb +99 -99
  32. data/lib/cyberarm_engine/console.rb +248 -248
  33. data/lib/cyberarm_engine/game_object.rb +244 -244
  34. data/lib/cyberarm_engine/game_state.rb +124 -124
  35. data/lib/cyberarm_engine/gosu_ext/draw_arc.rb +97 -97
  36. data/lib/cyberarm_engine/gosu_ext/draw_circle.rb +30 -30
  37. data/lib/cyberarm_engine/gosu_ext/draw_path.rb +17 -17
  38. data/lib/cyberarm_engine/model/material.rb +21 -21
  39. data/lib/cyberarm_engine/model/{model_object.rb → mesh.rb} +131 -131
  40. data/lib/cyberarm_engine/model/parser.rb +74 -74
  41. data/lib/cyberarm_engine/model/parsers/collada_parser.rb +138 -138
  42. data/lib/cyberarm_engine/model/parsers/wavefront_parser.rb +154 -154
  43. data/lib/cyberarm_engine/model.rb +216 -213
  44. data/lib/cyberarm_engine/model_cache.rb +31 -31
  45. data/lib/cyberarm_engine/notification.rb +82 -82
  46. data/lib/cyberarm_engine/notification_manager.rb +241 -241
  47. data/lib/cyberarm_engine/opengl/light.rb +52 -50
  48. data/lib/cyberarm_engine/opengl/orthographic_camera.rb +46 -46
  49. data/lib/cyberarm_engine/opengl/perspective_camera.rb +41 -38
  50. data/lib/cyberarm_engine/opengl/renderer/bounding_box_renderer.rb +249 -249
  51. data/lib/cyberarm_engine/opengl/renderer/g_buffer.rb +167 -165
  52. data/lib/cyberarm_engine/opengl/renderer/opengl_renderer.rb +307 -304
  53. data/lib/cyberarm_engine/opengl/renderer/renderer.rb +33 -33
  54. data/lib/cyberarm_engine/opengl/shader.rb +408 -406
  55. data/lib/cyberarm_engine/opengl/texture.rb +69 -69
  56. data/lib/cyberarm_engine/opengl.rb +53 -40
  57. data/lib/cyberarm_engine/ray.rb +56 -56
  58. data/lib/cyberarm_engine/stats.rb +200 -200
  59. data/lib/cyberarm_engine/text.rb +260 -260
  60. data/lib/cyberarm_engine/timer.rb +23 -23
  61. data/lib/cyberarm_engine/transform.rb +296 -296
  62. data/lib/cyberarm_engine/trees/aabb_node.rb +126 -0
  63. data/lib/cyberarm_engine/trees/aabb_tree.rb +55 -0
  64. data/lib/cyberarm_engine/trees/aabb_tree_debug.rb +29 -0
  65. data/lib/cyberarm_engine/ui/border_canvas.rb +102 -102
  66. data/lib/cyberarm_engine/ui/dsl.rb +142 -142
  67. data/lib/cyberarm_engine/ui/element.rb +662 -662
  68. data/lib/cyberarm_engine/ui/elements/button.rb +100 -100
  69. data/lib/cyberarm_engine/ui/elements/check_box.rb +54 -54
  70. data/lib/cyberarm_engine/ui/elements/container.rb +404 -410
  71. data/lib/cyberarm_engine/ui/elements/edit_box.rb +179 -179
  72. data/lib/cyberarm_engine/ui/elements/edit_line.rb +297 -297
  73. data/lib/cyberarm_engine/ui/elements/flow.rb +15 -15
  74. data/lib/cyberarm_engine/ui/elements/image.rb +72 -72
  75. data/lib/cyberarm_engine/ui/elements/list_box.rb +79 -79
  76. data/lib/cyberarm_engine/ui/elements/menu.rb +27 -27
  77. data/lib/cyberarm_engine/ui/elements/menu_item.rb +6 -6
  78. data/lib/cyberarm_engine/ui/elements/progress.rb +93 -93
  79. data/lib/cyberarm_engine/ui/elements/radio.rb +6 -6
  80. data/lib/cyberarm_engine/ui/elements/slider.rb +107 -107
  81. data/lib/cyberarm_engine/ui/elements/stack.rb +11 -11
  82. data/lib/cyberarm_engine/ui/elements/text_block.rb +216 -216
  83. data/lib/cyberarm_engine/ui/elements/toggle_button.rb +67 -67
  84. data/lib/cyberarm_engine/ui/event.rb +54 -54
  85. data/lib/cyberarm_engine/ui/gui_state.rb +321 -321
  86. data/lib/cyberarm_engine/ui/style.rb +50 -50
  87. data/lib/cyberarm_engine/ui/theme.rb +225 -225
  88. data/lib/cyberarm_engine/vector.rb +312 -312
  89. data/lib/cyberarm_engine/version.rb +4 -4
  90. data/lib/cyberarm_engine/window.rb +195 -195
  91. data/lib/cyberarm_engine.rb +70 -78
  92. data/mrbgem.rake +29 -29
  93. metadata +8 -7
@@ -1,107 +1,107 @@
1
- module CyberarmEngine
2
- class Element
3
- class Slider < Container
4
- class Handle < Button
5
- def initialize(*args)
6
- super(*args)
7
-
8
- event(:begin_drag)
9
- event(:drag_update)
10
- event(:end_drag)
11
-
12
- subscribe :begin_drag do |_sender, x, y, _button|
13
- @drag_start_pos = Vector.new(x, y)
14
-
15
- :handled
16
- end
17
-
18
- subscribe :drag_update do |_sender, x, y, _button|
19
- @parent.handle_dragged_to(x, y)
20
-
21
- :handled
22
- end
23
-
24
- subscribe :end_drag do
25
- @drag_start_pos = nil
26
-
27
- :handled
28
- end
29
- end
30
-
31
- def draggable?(button)
32
- button == :left
33
- end
34
- end
35
-
36
- attr_reader :value
37
- attr_accessor :range, :step_size
38
-
39
- def initialize(options = {}, block = nil)
40
- super(options, block)
41
-
42
- @range = @options[:range] || (0.0..1.0)
43
- @step_size = @options[:step] || 0.1
44
- @value = @options[:value] || (@range.first + @range.last) / 2
45
-
46
- @handle = Handle.new("", parent: self, theme: options[:theme], width: 8, height: 1.0) { close }
47
- add(@handle)
48
- end
49
-
50
- def recalculate
51
- _width = dimensional_size(@style.width, :width)
52
- _height = dimensional_size(@style.height, :height)
53
-
54
- @width = _width
55
- @height = _height
56
-
57
- position_handle
58
- @handle.recalculate
59
- @handle.update_background
60
-
61
- update_background
62
- end
63
-
64
- def position_handle
65
- @handle.x = @x + @handle.style.margin_left + @style.padding_left + @style.border_thickness_left +
66
- ((content_width - @handle.outer_width) * (@value - @range.min) / (@range.max - @range.min).to_f)
67
-
68
- @handle.y = @y + @handle.style.margin_top + @style.border_thickness_top + @style.padding_top
69
- end
70
-
71
- def draw
72
- super
73
-
74
- @handle.draw
75
- end
76
-
77
- def update
78
- super
79
-
80
- @tip = format("%.2f", value.to_f)
81
- @handle.tip = @tip
82
- end
83
-
84
- def holding_left_mouse_button(_sender, x, y)
85
- handle_dragged_to(x, y)
86
-
87
- :handled
88
- end
89
-
90
- def handle_dragged_to(x, _y)
91
- @ratio = ((x - @handle.width / 2.0) - @x) / (content_width - @handle.outer_width.to_f)
92
-
93
- self.value = @ratio.clamp(0.0, 1.0) * (@range.max - @range.min) + @range.min
94
- end
95
-
96
- def value=(n)
97
- @value = n
98
- position_handle
99
- @handle.recalculate
100
-
101
- root.gui_state.request_repaint
102
-
103
- publish(:changed, @value)
104
- end
105
- end
106
- end
107
- end
1
+ module CyberarmEngine
2
+ class Element
3
+ class Slider < Container
4
+ class Handle < Button
5
+ def initialize(*args)
6
+ super(*args)
7
+
8
+ event(:begin_drag)
9
+ event(:drag_update)
10
+ event(:end_drag)
11
+
12
+ subscribe :begin_drag do |_sender, x, y, _button|
13
+ @drag_start_pos = Vector.new(x, y)
14
+
15
+ :handled
16
+ end
17
+
18
+ subscribe :drag_update do |_sender, x, y, _button|
19
+ @parent.handle_dragged_to(x, y)
20
+
21
+ :handled
22
+ end
23
+
24
+ subscribe :end_drag do
25
+ @drag_start_pos = nil
26
+
27
+ :handled
28
+ end
29
+ end
30
+
31
+ def draggable?(button)
32
+ button == :left
33
+ end
34
+ end
35
+
36
+ attr_reader :value
37
+ attr_accessor :range, :step_size
38
+
39
+ def initialize(options = {}, block = nil)
40
+ super(options, block)
41
+
42
+ @range = @options[:range] || (0.0..1.0)
43
+ @step_size = @options[:step] || 0.1
44
+ @value = @options[:value] || (@range.first + @range.last) / 2
45
+
46
+ @handle = Handle.new("", parent: self, theme: options[:theme], width: 8, height: 1.0) { close }
47
+ add(@handle)
48
+ end
49
+
50
+ def recalculate
51
+ _width = dimensional_size(@style.width, :width)
52
+ _height = dimensional_size(@style.height, :height)
53
+
54
+ @width = _width
55
+ @height = _height
56
+
57
+ position_handle
58
+ @handle.recalculate
59
+ @handle.update_background
60
+
61
+ update_background
62
+ end
63
+
64
+ def position_handle
65
+ @handle.x = @x + @handle.style.margin_left + @style.padding_left + @style.border_thickness_left +
66
+ ((content_width - @handle.outer_width) * (@value - @range.min) / (@range.max - @range.min).to_f)
67
+
68
+ @handle.y = @y + @handle.style.margin_top + @style.border_thickness_top + @style.padding_top
69
+ end
70
+
71
+ def draw
72
+ super
73
+
74
+ @handle.draw
75
+ end
76
+
77
+ def update
78
+ super
79
+
80
+ @tip = format("%.2f", value.to_f)
81
+ @handle.tip = @tip
82
+ end
83
+
84
+ def holding_left_mouse_button(_sender, x, y)
85
+ handle_dragged_to(x, y)
86
+
87
+ :handled
88
+ end
89
+
90
+ def handle_dragged_to(x, _y)
91
+ @ratio = ((x - @handle.width / 2.0) - @x) / (content_width - @handle.outer_width.to_f)
92
+
93
+ self.value = @ratio.clamp(0.0, 1.0) * (@range.max - @range.min) + @range.min
94
+ end
95
+
96
+ def value=(n)
97
+ @value = n
98
+ position_handle
99
+ @handle.recalculate
100
+
101
+ root.gui_state.request_repaint
102
+
103
+ publish(:changed, @value)
104
+ end
105
+ end
106
+ end
107
+ end
@@ -1,11 +1,11 @@
1
- module CyberarmEngine
2
- class Element
3
- class Stack < Container
4
- def layout
5
- @children.each do |child|
6
- move_to_next_line(child)
7
- end
8
- end
9
- end
10
- end
11
- end
1
+ module CyberarmEngine
2
+ class Element
3
+ class Stack < Container
4
+ def layout
5
+ @children.each do |child|
6
+ move_to_next_line(child)
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -1,216 +1,216 @@
1
- module CyberarmEngine
2
- class Element
3
- class TextBlock < Element
4
- def initialize(text, options = {}, block = nil)
5
- super(options, block)
6
-
7
- @text = Text.new(
8
- text, font: @options[:font], z: @z, color: @options[:color],
9
- size: @options[:text_size], shadow: @options[:text_shadow],
10
- static: @options[:text_static],
11
- shadow_size: @options[:text_shadow_size],
12
- shadow_color: @options[:text_shadow_color],
13
- border: @options[:text_border],
14
- border_size: @options[:text_border_size],
15
- border_color: @options[:text_border_color]
16
- )
17
-
18
- @raw_text = text
19
- end
20
-
21
- def update
22
- super
23
-
24
- if @text.textobject.name != safe_style_fetch(:font)
25
- set_font
26
- root.gui_state.request_recalculate
27
- end
28
- end
29
-
30
- def render
31
- # Gosu.clip_to is too expensive to always use so check if we actually need it.
32
- if @text.width > width || @text.height > height
33
- Gosu.clip_to(@x, @y, width, height) do
34
- @text.draw
35
- end
36
- else
37
- @text.draw
38
- end
39
- end
40
-
41
- def layout
42
- unless @enabled
43
- @text.color = @style.disabled[:color]
44
- else
45
- @text.color = @style.color
46
- end
47
-
48
- @width = 0
49
- @height = 0
50
-
51
- _width = dimensional_size(@style.width, :width)
52
- _height = dimensional_size(@style.height, :height)
53
-
54
- handle_text_wrapping(_width)
55
-
56
- @width = _width || @text.width.floor
57
- @height = _height || @text.height.floor
58
-
59
- @text.y = @style.border_thickness_top + @style.padding_top + @y
60
- @text.z = @z + 3
61
-
62
- if (text_alignment = @options[:text_align] || @options[:text_h_align])
63
- case text_alignment
64
- when :left
65
- @text.x = @style.border_thickness_left + @style.padding_left + @x
66
- when :center
67
- @text.x = if @text.width <= width
68
- @x + width / 2 - @text.width / 2
69
- else # Act as left aligned
70
- @style.border_thickness_left + @style.padding_left + @x
71
- end
72
- when :right
73
- @text.x = @x + outer_width - (@text.width + @style.border_thickness_right + @style.padding_right)
74
- end
75
- end
76
-
77
- if (vertical_alignment = @options[:text_v_align])
78
- case vertical_alignment
79
- when :center
80
- @text.y = if @text.height <= height
81
- @y + height / 2 - @text.height / 2
82
- else
83
- @style.border_thickness_top + @style.padding_top + @y
84
- end
85
- when :bottom
86
- @text.y = @y + outer_height - (@text.height + @style.border_thickness_bottom + @style.padding_bottom)
87
- end
88
- end
89
-
90
- update_background
91
- end
92
-
93
- def handle_text_wrapping(max_width)
94
- max_width ||= @parent&.content_width
95
- max_width ||= @x - (window.width + noncontent_width)
96
- wrap_behavior = style.text_wrap
97
- copy = @raw_text.to_s.dup
98
-
99
- # Only perform text wrapping: if it is enabled, is possible to wrap, and text is too long to fit on one line
100
- if wrap_behavior != :none && line_width(copy[0]) <= max_width && line_width(copy) > max_width
101
- breaks = [] # list of indexes to insert a line break
102
- line_start = 0
103
- line_end = copy.length
104
-
105
- stalled = false
106
- stalled_interations = 0
107
- max_stalled_iterations = 10
108
- checked_copy_length = line_width(copy[line_start..line_end])
109
-
110
- # find length of lines
111
- while line_width(copy[line_start..line_end]) > max_width && stalled_interations < max_stalled_iterations
112
- search_start = line_start
113
- search_end = line_end
114
-
115
- # Perform a binary search to find length of line
116
- while search_start < search_end
117
- midpoint = ((search_start.to_f + search_end) / 2.0).floor
118
-
119
- if line_width(copy[line_start..midpoint]) > max_width
120
- search_end = midpoint
121
- else
122
- search_start = midpoint + 1
123
- end
124
- end
125
-
126
- if wrap_behavior == :word_wrap
127
- word_search_end = search_end
128
- failed = false
129
-
130
- until(copy[word_search_end].to_s.match(/[[:punct:]]| /))
131
- word_search_end -= 1
132
-
133
- if word_search_end <= 1 || word_search_end < line_start
134
- failed = true
135
- break
136
- end
137
- end
138
-
139
- line_start = failed ? search_end : word_search_end + 1 # walk in front of punctuation
140
- else
141
- line_start = search_end
142
- end
143
-
144
- breaks << line_start
145
-
146
- # Prevent locking up due to outer while loop text width < max_width check not being satisfied.
147
- stalled = checked_copy_length == line_width(copy[line_start..line_end])
148
- checked_copy_length = line_width(copy[line_start..line_end])
149
-
150
- stalled_interations += 1 if stalled
151
- stalled_interations = 0 unless stalled
152
- end
153
-
154
- breaks.each_with_index do |pos, index|
155
- copy.insert(pos + index, "\n") if pos + index >= 0 && pos + index < copy.length
156
- end
157
- end
158
-
159
- @text.text = copy
160
- end
161
-
162
- def line_width(text)
163
- (@text.textobject.markup_width(text.to_s) + noncontent_width)
164
- end
165
-
166
- def value
167
- @raw_text
168
- end
169
-
170
- def value=(value)
171
- old_value = @raw_text
172
- @raw_text = value.to_s.chomp
173
-
174
- old_width = width
175
- old_height = height
176
-
177
- if old_width != width || old_height != height
178
- root.gui_state.request_recalculate
179
- else
180
- recalculate
181
- end
182
-
183
- root.gui_state.request_repaint if old_value != @raw_text
184
-
185
- publish(:changed, self.value)
186
- end
187
- end
188
-
189
- class Banner < TextBlock
190
- end
191
-
192
- class Title < TextBlock
193
- end
194
-
195
- class Subtitle < TextBlock
196
- end
197
-
198
- class Tagline < TextBlock
199
- end
200
-
201
- class Caption < TextBlock
202
- end
203
-
204
- class Para < TextBlock
205
- end
206
-
207
- class Inscription < TextBlock
208
- end
209
-
210
- class ToolTip < TextBlock
211
- end
212
-
213
- class Link < TextBlock
214
- end
215
- end
216
- end
1
+ module CyberarmEngine
2
+ class Element
3
+ class TextBlock < Element
4
+ def initialize(text, options = {}, block = nil)
5
+ super(options, block)
6
+
7
+ @text = Text.new(
8
+ text, font: @options[:font], z: @z, color: @options[:color],
9
+ size: @options[:text_size], shadow: @options[:text_shadow],
10
+ static: @options[:text_static],
11
+ shadow_size: @options[:text_shadow_size],
12
+ shadow_color: @options[:text_shadow_color],
13
+ border: @options[:text_border],
14
+ border_size: @options[:text_border_size],
15
+ border_color: @options[:text_border_color]
16
+ )
17
+
18
+ @raw_text = text
19
+ end
20
+
21
+ def update
22
+ super
23
+
24
+ if @text.textobject.name != safe_style_fetch(:font)
25
+ set_font
26
+ root.gui_state.request_recalculate
27
+ end
28
+ end
29
+
30
+ def render
31
+ # Gosu.clip_to is too expensive to always use so check if we actually need it.
32
+ if @text.width > width || @text.height > height
33
+ Gosu.clip_to(@x, @y, width, height) do
34
+ @text.draw
35
+ end
36
+ else
37
+ @text.draw
38
+ end
39
+ end
40
+
41
+ def layout
42
+ unless @enabled
43
+ @text.color = @style.disabled[:color]
44
+ else
45
+ @text.color = @style.color
46
+ end
47
+
48
+ @width = 0
49
+ @height = 0
50
+
51
+ _width = dimensional_size(@style.width, :width)
52
+ _height = dimensional_size(@style.height, :height)
53
+
54
+ handle_text_wrapping(_width)
55
+
56
+ @width = _width || @text.width.floor
57
+ @height = _height || @text.height.floor
58
+
59
+ @text.y = @style.border_thickness_top + @style.padding_top + @y
60
+ @text.z = @z + 3
61
+
62
+ if (text_alignment = @options[:text_align] || @options[:text_h_align])
63
+ case text_alignment
64
+ when :left
65
+ @text.x = @style.border_thickness_left + @style.padding_left + @x
66
+ when :center
67
+ @text.x = if @text.width <= width
68
+ @x + width / 2 - @text.width / 2
69
+ else # Act as left aligned
70
+ @style.border_thickness_left + @style.padding_left + @x
71
+ end
72
+ when :right
73
+ @text.x = @x + outer_width - (@text.width + @style.border_thickness_right + @style.padding_right)
74
+ end
75
+ end
76
+
77
+ if (vertical_alignment = @options[:text_v_align])
78
+ case vertical_alignment
79
+ when :center
80
+ @text.y = if @text.height <= height
81
+ @y + height / 2 - @text.height / 2
82
+ else
83
+ @style.border_thickness_top + @style.padding_top + @y
84
+ end
85
+ when :bottom
86
+ @text.y = @y + outer_height - (@text.height + @style.border_thickness_bottom + @style.padding_bottom)
87
+ end
88
+ end
89
+
90
+ update_background
91
+ end
92
+
93
+ def handle_text_wrapping(max_width)
94
+ max_width ||= @parent&.content_width
95
+ max_width ||= @x - (window.width + noncontent_width)
96
+ wrap_behavior = style.text_wrap
97
+ copy = @raw_text.to_s.dup
98
+
99
+ # Only perform text wrapping: if it is enabled, is possible to wrap, and text is too long to fit on one line
100
+ if wrap_behavior != :none && line_width(copy[0]) <= max_width && line_width(copy) > max_width
101
+ breaks = [] # list of indexes to insert a line break
102
+ line_start = 0
103
+ line_end = copy.length
104
+
105
+ stalled = false
106
+ stalled_interations = 0
107
+ max_stalled_iterations = 10
108
+ checked_copy_length = line_width(copy[line_start..line_end])
109
+
110
+ # find length of lines
111
+ while line_width(copy[line_start..line_end]) > max_width && stalled_interations < max_stalled_iterations
112
+ search_start = line_start
113
+ search_end = line_end
114
+
115
+ # Perform a binary search to find length of line
116
+ while search_start < search_end
117
+ midpoint = ((search_start.to_f + search_end) / 2.0).floor
118
+
119
+ if line_width(copy[line_start..midpoint]) > max_width
120
+ search_end = midpoint
121
+ else
122
+ search_start = midpoint + 1
123
+ end
124
+ end
125
+
126
+ if wrap_behavior == :word_wrap
127
+ word_search_end = search_end
128
+ failed = false
129
+
130
+ until(copy[word_search_end].to_s.match(/[[:punct:]]| /))
131
+ word_search_end -= 1
132
+
133
+ if word_search_end <= 1 || word_search_end < line_start
134
+ failed = true
135
+ break
136
+ end
137
+ end
138
+
139
+ line_start = failed ? search_end : word_search_end + 1 # walk in front of punctuation
140
+ else
141
+ line_start = search_end
142
+ end
143
+
144
+ breaks << line_start
145
+
146
+ # Prevent locking up due to outer while loop text width < max_width check not being satisfied.
147
+ stalled = checked_copy_length == line_width(copy[line_start..line_end])
148
+ checked_copy_length = line_width(copy[line_start..line_end])
149
+
150
+ stalled_interations += 1 if stalled
151
+ stalled_interations = 0 unless stalled
152
+ end
153
+
154
+ breaks.each_with_index do |pos, index|
155
+ copy.insert(pos + index, "\n") if pos + index >= 0 && pos + index < copy.length
156
+ end
157
+ end
158
+
159
+ @text.text = copy
160
+ end
161
+
162
+ def line_width(text)
163
+ (@text.textobject.markup_width(text.to_s) + noncontent_width)
164
+ end
165
+
166
+ def value
167
+ @raw_text
168
+ end
169
+
170
+ def value=(value)
171
+ old_value = @raw_text
172
+ @raw_text = value.to_s.chomp
173
+
174
+ old_width = width
175
+ old_height = height
176
+
177
+ if old_width != width || old_height != height
178
+ root.gui_state.request_recalculate
179
+ else
180
+ recalculate
181
+ end
182
+
183
+ root.gui_state.request_repaint if old_value != @raw_text
184
+
185
+ publish(:changed, self.value)
186
+ end
187
+ end
188
+
189
+ class Banner < TextBlock
190
+ end
191
+
192
+ class Title < TextBlock
193
+ end
194
+
195
+ class Subtitle < TextBlock
196
+ end
197
+
198
+ class Tagline < TextBlock
199
+ end
200
+
201
+ class Caption < TextBlock
202
+ end
203
+
204
+ class Para < TextBlock
205
+ end
206
+
207
+ class Inscription < TextBlock
208
+ end
209
+
210
+ class ToolTip < TextBlock
211
+ end
212
+
213
+ class Link < TextBlock
214
+ end
215
+ end
216
+ end