cyberarm_engine 0.24.4 → 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.
- checksums.yaml +4 -4
- data/.gitignore +8 -8
- data/.rubocop.yml +7 -7
- data/.travis.yml +5 -5
- data/Gemfile +6 -6
- data/Gemfile.lock +24 -0
- data/LICENSE.txt +21 -21
- data/README.md +74 -74
- data/Rakefile +10 -10
- data/assets/shaders/fragment/g_buffer.glsl +30 -30
- data/assets/shaders/fragment/lighting.glsl +115 -69
- data/assets/shaders/include/light_struct.glsl +11 -11
- data/assets/shaders/include/material_struct.glsl +16 -16
- data/assets/shaders/vertex/g_buffer.glsl +28 -28
- data/assets/shaders/vertex/lighting.glsl +24 -24
- data/bin/console +14 -14
- data/bin/setup +8 -8
- data/cyberarm_engine.gemspec +36 -36
- data/lib/cyberarm_engine/animator.rb +219 -219
- data/lib/cyberarm_engine/background.rb +180 -179
- data/lib/cyberarm_engine/background_image.rb +93 -93
- data/lib/cyberarm_engine/background_nine_slice.rb +142 -142
- data/lib/cyberarm_engine/bounding_box.rb +150 -150
- data/lib/cyberarm_engine/builtin/intro_state.rb +130 -130
- data/lib/cyberarm_engine/cache/download_manager.rb +123 -123
- data/lib/cyberarm_engine/cache.rb +4 -4
- data/lib/cyberarm_engine/common.rb +128 -128
- data/lib/cyberarm_engine/config_file.rb +46 -46
- data/lib/cyberarm_engine/console/command.rb +157 -157
- data/lib/cyberarm_engine/console/commands/help_command.rb +43 -43
- data/lib/cyberarm_engine/console/subcommand.rb +99 -99
- data/lib/cyberarm_engine/console.rb +248 -248
- data/lib/cyberarm_engine/game_object.rb +244 -244
- data/lib/cyberarm_engine/game_state.rb +124 -124
- data/lib/cyberarm_engine/gosu_ext/draw_arc.rb +97 -97
- data/lib/cyberarm_engine/gosu_ext/draw_circle.rb +30 -30
- data/lib/cyberarm_engine/gosu_ext/draw_path.rb +17 -17
- data/lib/cyberarm_engine/model/material.rb +21 -21
- data/lib/cyberarm_engine/model/{model_object.rb → mesh.rb} +131 -131
- data/lib/cyberarm_engine/model/parser.rb +74 -74
- data/lib/cyberarm_engine/model/parsers/collada_parser.rb +138 -138
- data/lib/cyberarm_engine/model/parsers/wavefront_parser.rb +154 -154
- data/lib/cyberarm_engine/model.rb +216 -213
- data/lib/cyberarm_engine/model_cache.rb +31 -31
- data/lib/cyberarm_engine/notification.rb +82 -82
- data/lib/cyberarm_engine/notification_manager.rb +241 -241
- data/lib/cyberarm_engine/opengl/light.rb +52 -50
- data/lib/cyberarm_engine/opengl/orthographic_camera.rb +46 -46
- data/lib/cyberarm_engine/opengl/perspective_camera.rb +41 -38
- data/lib/cyberarm_engine/opengl/renderer/bounding_box_renderer.rb +249 -249
- data/lib/cyberarm_engine/opengl/renderer/g_buffer.rb +167 -165
- data/lib/cyberarm_engine/opengl/renderer/opengl_renderer.rb +307 -304
- data/lib/cyberarm_engine/opengl/renderer/renderer.rb +33 -33
- data/lib/cyberarm_engine/opengl/shader.rb +408 -406
- data/lib/cyberarm_engine/opengl/texture.rb +69 -69
- data/lib/cyberarm_engine/opengl.rb +53 -40
- data/lib/cyberarm_engine/ray.rb +56 -56
- data/lib/cyberarm_engine/stats.rb +200 -200
- data/lib/cyberarm_engine/text.rb +260 -260
- data/lib/cyberarm_engine/timer.rb +23 -23
- data/lib/cyberarm_engine/transform.rb +296 -296
- data/lib/cyberarm_engine/trees/aabb_node.rb +126 -0
- data/lib/cyberarm_engine/trees/aabb_tree.rb +55 -0
- data/lib/cyberarm_engine/trees/aabb_tree_debug.rb +29 -0
- data/lib/cyberarm_engine/ui/border_canvas.rb +102 -102
- data/lib/cyberarm_engine/ui/dsl.rb +142 -142
- data/lib/cyberarm_engine/ui/element.rb +662 -662
- data/lib/cyberarm_engine/ui/elements/button.rb +100 -100
- data/lib/cyberarm_engine/ui/elements/check_box.rb +54 -54
- data/lib/cyberarm_engine/ui/elements/container.rb +404 -404
- data/lib/cyberarm_engine/ui/elements/edit_box.rb +179 -179
- data/lib/cyberarm_engine/ui/elements/edit_line.rb +297 -297
- data/lib/cyberarm_engine/ui/elements/flow.rb +15 -15
- data/lib/cyberarm_engine/ui/elements/image.rb +72 -72
- data/lib/cyberarm_engine/ui/elements/list_box.rb +79 -79
- data/lib/cyberarm_engine/ui/elements/menu.rb +27 -27
- data/lib/cyberarm_engine/ui/elements/menu_item.rb +6 -6
- data/lib/cyberarm_engine/ui/elements/progress.rb +93 -93
- data/lib/cyberarm_engine/ui/elements/radio.rb +6 -6
- data/lib/cyberarm_engine/ui/elements/slider.rb +107 -107
- data/lib/cyberarm_engine/ui/elements/stack.rb +11 -11
- data/lib/cyberarm_engine/ui/elements/text_block.rb +216 -216
- data/lib/cyberarm_engine/ui/elements/toggle_button.rb +67 -67
- data/lib/cyberarm_engine/ui/event.rb +54 -54
- data/lib/cyberarm_engine/ui/gui_state.rb +321 -321
- data/lib/cyberarm_engine/ui/style.rb +50 -50
- data/lib/cyberarm_engine/ui/theme.rb +225 -225
- data/lib/cyberarm_engine/vector.rb +312 -312
- data/lib/cyberarm_engine/version.rb +4 -4
- data/lib/cyberarm_engine/window.rb +195 -195
- data/lib/cyberarm_engine.rb +70 -78
- data/mrbgem.rake +29 -29
- metadata +8 -7
@@ -1,404 +1,404 @@
|
|
1
|
-
module CyberarmEngine
|
2
|
-
class Element
|
3
|
-
class Container < Element
|
4
|
-
include Common
|
5
|
-
|
6
|
-
attr_accessor :stroke_color, :fill_color
|
7
|
-
attr_reader :children, :gui_state, :scroll_position, :scroll_target_position
|
8
|
-
|
9
|
-
def self.current_container
|
10
|
-
@@current_container
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.current_container=(container)
|
14
|
-
raise ArgumentError, "Expected container to an an instance of CyberarmEngine::Element::Container, got #{container.class}" unless container.is_a?(CyberarmEngine::Element::Container)
|
15
|
-
|
16
|
-
@@current_container = container
|
17
|
-
end
|
18
|
-
|
19
|
-
def initialize(options = {}, block = nil)
|
20
|
-
@gui_state = options.delete(:gui_state)
|
21
|
-
super
|
22
|
-
|
23
|
-
@last_scroll_position = Vector.new(0, 0)
|
24
|
-
@scroll_position = Vector.new(0, 0)
|
25
|
-
@scroll_target_position = Vector.new(0, 0)
|
26
|
-
@scroll_chunk = 120
|
27
|
-
@scroll_speed = 40
|
28
|
-
|
29
|
-
@text_color = options[:color]
|
30
|
-
|
31
|
-
@children = []
|
32
|
-
|
33
|
-
event(:window_size_changed)
|
34
|
-
end
|
35
|
-
|
36
|
-
def build
|
37
|
-
@block.call(self) if @block
|
38
|
-
|
39
|
-
root.gui_state.request_recalculate_for(self)
|
40
|
-
end
|
41
|
-
|
42
|
-
def add(element)
|
43
|
-
@children << element
|
44
|
-
|
45
|
-
root.gui_state.request_recalculate_for(self)
|
46
|
-
end
|
47
|
-
|
48
|
-
def remove(element)
|
49
|
-
root.gui_state.request_recalculate_for(self) if @children.delete(element)
|
50
|
-
end
|
51
|
-
|
52
|
-
def append(&block)
|
53
|
-
old_container = CyberarmEngine::Element::Container.current_container
|
54
|
-
|
55
|
-
CyberarmEngine::Element::Container.current_container = self
|
56
|
-
block.call(self) if block
|
57
|
-
|
58
|
-
CyberarmEngine::Element::Container.current_container = old_container
|
59
|
-
|
60
|
-
root.gui_state.request_recalculate_for(self)
|
61
|
-
end
|
62
|
-
|
63
|
-
def clear(&block)
|
64
|
-
@children.clear
|
65
|
-
|
66
|
-
old_container = CyberarmEngine::Element::Container.current_container
|
67
|
-
|
68
|
-
CyberarmEngine::Element::Container.current_container = self
|
69
|
-
block.call(self) if block
|
70
|
-
|
71
|
-
CyberarmEngine::Element::Container.current_container = old_container
|
72
|
-
|
73
|
-
root.gui_state.request_recalculate_for(self)
|
74
|
-
end
|
75
|
-
|
76
|
-
def render
|
77
|
-
Gosu.clip_to(
|
78
|
-
@x + @style.border_thickness_left + @style.padding_left,
|
79
|
-
@y + @style.border_thickness_top + @style.padding_top,
|
80
|
-
content_width + 1,
|
81
|
-
content_height + 1
|
82
|
-
) do
|
83
|
-
Gosu.translate(@scroll_position.x, @scroll_position.y) do
|
84
|
-
@children.each(&:draw)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def debug_draw
|
90
|
-
super
|
91
|
-
|
92
|
-
@children.each do |child|
|
93
|
-
child.debug_draw
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def update
|
98
|
-
update_scroll if @style.scroll
|
99
|
-
@children.each(&:update)
|
100
|
-
end
|
101
|
-
|
102
|
-
def hit_element?(x, y)
|
103
|
-
return unless hit?(x, y)
|
104
|
-
|
105
|
-
# Offset child hit point by scroll position/offset
|
106
|
-
child_x = x - @scroll_position.x
|
107
|
-
child_y = y - @scroll_position.y
|
108
|
-
|
109
|
-
@children.reverse_each do |child|
|
110
|
-
next unless child.visible?
|
111
|
-
|
112
|
-
case child
|
113
|
-
when Container
|
114
|
-
if element = child.hit_element?(child_x, child_y)
|
115
|
-
return element
|
116
|
-
end
|
117
|
-
else
|
118
|
-
return child if child.hit?(child_x, child_y)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
self if hit?(x, y)
|
123
|
-
end
|
124
|
-
|
125
|
-
def update_child_element_visibity(child)
|
126
|
-
child.element_visible = child.x >= (@x - @scroll_position.x) - child.width && child.x <= (@x - @scroll_position.x) + width &&
|
127
|
-
child.y >= (@y - @scroll_position.y) - child.height && child.y <= (@y - @scroll_position.y) + height
|
128
|
-
end
|
129
|
-
|
130
|
-
def update_scroll
|
131
|
-
dt = window.dt.clamp(0.000001, 0.025)
|
132
|
-
@scroll_position.x += (((@scroll_target_position.x - @scroll_position.x) * (@scroll_speed / 4.0) * 0.98) * dt).round
|
133
|
-
@scroll_position.y += (((@scroll_target_position.y - @scroll_position.y) * (@scroll_speed / 4.0) * 0.98) * dt).round
|
134
|
-
|
135
|
-
# Scrolled PAST top
|
136
|
-
if @scroll_position.y > 0
|
137
|
-
@scroll_target_position.y = 0
|
138
|
-
|
139
|
-
# Scrolled PAST bottom
|
140
|
-
elsif @scroll_position.y < -max_scroll_height
|
141
|
-
@scroll_target_position.y = -max_scroll_height
|
142
|
-
end
|
143
|
-
|
144
|
-
if @last_scroll_position != @scroll_position
|
145
|
-
@children.each { |child| update_child_element_visibity(child) }
|
146
|
-
root.gui_state.request_repaint
|
147
|
-
end
|
148
|
-
|
149
|
-
@last_scroll_position.x = @scroll_position.x
|
150
|
-
@last_scroll_position.y = @scroll_position.y
|
151
|
-
end
|
152
|
-
|
153
|
-
def recalculate
|
154
|
-
@current_position = Vector.new(@style.margin_left + @style.padding_left, @style.margin_top + @style.padding_top)
|
155
|
-
|
156
|
-
return unless visible?
|
157
|
-
|
158
|
-
Stats.frame&.increment(:gui_recalculations)
|
159
|
-
|
160
|
-
# s = Gosu.milliseconds
|
161
|
-
|
162
|
-
stylize
|
163
|
-
layout
|
164
|
-
|
165
|
-
# Old sizes MUST be determined AFTER call to layout
|
166
|
-
old_width = width
|
167
|
-
old_height = height
|
168
|
-
|
169
|
-
@cached_scroll_width = nil
|
170
|
-
@cached_scroll_height = nil
|
171
|
-
|
172
|
-
if is_root?
|
173
|
-
@width = @style.width = window.width
|
174
|
-
@height = @style.height = window.height
|
175
|
-
else
|
176
|
-
@width = 0
|
177
|
-
@height = 0
|
178
|
-
|
179
|
-
_width = dimensional_size(@style.width, :width)
|
180
|
-
_height = dimensional_size(@style.height, :height)
|
181
|
-
|
182
|
-
@width = _width || (@children.map { |c| c.x + c.outer_width }.max || 0).floor
|
183
|
-
@height = _height || (@children.map { |c| c.y + c.outer_height }.max || 0).floor
|
184
|
-
end
|
185
|
-
|
186
|
-
# FIXME: Correctly handle alignment when element has siblings
|
187
|
-
# FIXME: Enable alignment for any element, not just containers
|
188
|
-
if @style.v_align
|
189
|
-
space = space_available_height
|
190
|
-
|
191
|
-
case @style.v_align
|
192
|
-
when :center
|
193
|
-
@y = parent.height / 2 - height / 2
|
194
|
-
when :bottom
|
195
|
-
@y = parent.height - height
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
if @style.h_align
|
200
|
-
space = space_available_width
|
201
|
-
|
202
|
-
case @style.h_align
|
203
|
-
when :center
|
204
|
-
@x = parent.width / 2 - width / 2
|
205
|
-
when :right
|
206
|
-
@x = parent.width - width
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
# t = Gosu.milliseconds
|
211
|
-
# Move children to parent after positioning
|
212
|
-
@children.each do |child|
|
213
|
-
child.x += (@x + @style.border_thickness_left) - style.margin_left
|
214
|
-
child.y += (@y + @style.border_thickness_top) - style.margin_top
|
215
|
-
|
216
|
-
child.stylize
|
217
|
-
child.recalculate
|
218
|
-
child.reposition # TODO: Implement top,bottom,left,center, and right positioning
|
219
|
-
|
220
|
-
Stats.frame&.increment(:gui_recalculations)
|
221
|
-
|
222
|
-
update_child_element_visibity(child)
|
223
|
-
end
|
224
|
-
# puts "TOOK: #{Gosu.milliseconds - t}ms to recalculate #{self.class}:0x#{self.object_id.to_s(16)}'s #{@children.count} children"
|
225
|
-
|
226
|
-
update_background
|
227
|
-
|
228
|
-
# Fixes resized container scrolled past bottom
|
229
|
-
if old_height != @height
|
230
|
-
self.scroll_top = -@scroll_position.y
|
231
|
-
@scroll_target_position.y = @scroll_position.y
|
232
|
-
end
|
233
|
-
|
234
|
-
# Fixes resized container that is scrolled down from being stuck overscrolled when resized
|
235
|
-
if scroll_height < height
|
236
|
-
@scroll_target_position.y = 0
|
237
|
-
end
|
238
|
-
|
239
|
-
recalculate_if_size_changed
|
240
|
-
|
241
|
-
# puts "TOOK: #{Gosu.milliseconds - s}ms to recalculate #{self.class}:0x#{self.object_id.to_s(16)}"
|
242
|
-
end
|
243
|
-
|
244
|
-
def layout
|
245
|
-
raise "Not overridden"
|
246
|
-
end
|
247
|
-
|
248
|
-
def max_width
|
249
|
-
# _width = dimensional_size(@style.width, :width)
|
250
|
-
# if _width
|
251
|
-
# outer_width
|
252
|
-
# else
|
253
|
-
# window.width - (@parent ? @parent.style.margin_right + @style.margin_right : @style.margin_right)
|
254
|
-
# end
|
255
|
-
|
256
|
-
outer_width
|
257
|
-
end
|
258
|
-
|
259
|
-
def fits_on_line?(element) # Flow
|
260
|
-
@current_position.x + element.outer_width <= max_width &&
|
261
|
-
@current_position.x + element.outer_width <= window.width
|
262
|
-
end
|
263
|
-
|
264
|
-
def position_on_current_line(element) # Flow
|
265
|
-
element.x = element.style.margin_left + @current_position.x
|
266
|
-
element.y = element.style.margin_top + @current_position.y
|
267
|
-
|
268
|
-
@current_position.x += element.outer_width
|
269
|
-
end
|
270
|
-
|
271
|
-
def tallest_neighbor(querier, _y_position) # Flow
|
272
|
-
response = querier
|
273
|
-
@children.each do |child|
|
274
|
-
response = child if child.outer_height > response.outer_height
|
275
|
-
break if child == querier
|
276
|
-
end
|
277
|
-
|
278
|
-
response
|
279
|
-
end
|
280
|
-
|
281
|
-
def position_on_next_line(element) # Flow
|
282
|
-
@current_position.x = @style.margin_left + @style.padding_left
|
283
|
-
@current_position.y += tallest_neighbor(element, @current_position.y).outer_height
|
284
|
-
|
285
|
-
element.x = element.style.margin_left + @current_position.x
|
286
|
-
element.y = element.style.margin_top + @current_position.y
|
287
|
-
|
288
|
-
@current_position.x += element.outer_width
|
289
|
-
end
|
290
|
-
|
291
|
-
def move_to_next_line(element) # Stack
|
292
|
-
element.x = element.style.margin_left + @current_position.x
|
293
|
-
element.y = element.style.margin_top + @current_position.y
|
294
|
-
|
295
|
-
@current_position.y += element.outer_height
|
296
|
-
end
|
297
|
-
|
298
|
-
def mouse_wheel_up(sender, x, y)
|
299
|
-
return unless @style.scroll
|
300
|
-
|
301
|
-
# Allow overscrolling UP, only if one can scroll DOWN
|
302
|
-
if height < scroll_height
|
303
|
-
if @scroll_target_position.y > 0
|
304
|
-
@scroll_target_position.y = @scroll_chunk
|
305
|
-
else
|
306
|
-
@scroll_target_position.y += @scroll_chunk
|
307
|
-
end
|
308
|
-
|
309
|
-
return :handled
|
310
|
-
end
|
311
|
-
end
|
312
|
-
|
313
|
-
def mouse_wheel_down(sender, x, y)
|
314
|
-
return unless @style.scroll
|
315
|
-
|
316
|
-
return unless height < scroll_height
|
317
|
-
|
318
|
-
if @scroll_target_position.y > 0
|
319
|
-
@scroll_target_position.y = -@scroll_chunk
|
320
|
-
else
|
321
|
-
@scroll_target_position.y -= @scroll_chunk
|
322
|
-
end
|
323
|
-
|
324
|
-
return :handled
|
325
|
-
end
|
326
|
-
|
327
|
-
def scroll_jump_to_top(sender, x, y)
|
328
|
-
return unless @style.scroll
|
329
|
-
|
330
|
-
@scroll_position.y = 0
|
331
|
-
@scroll_target_position.y = 0
|
332
|
-
|
333
|
-
return :handled
|
334
|
-
end
|
335
|
-
|
336
|
-
def scroll_jump_to_end(sender, x, y)
|
337
|
-
return unless @style.scroll
|
338
|
-
|
339
|
-
@scroll_position.y = -max_scroll_height
|
340
|
-
@scroll_target_position.y = -max_scroll_height
|
341
|
-
|
342
|
-
return :handled
|
343
|
-
end
|
344
|
-
|
345
|
-
def scroll_page_up(sender, x, y)
|
346
|
-
return unless @style.scroll
|
347
|
-
|
348
|
-
@scroll_position.y += height
|
349
|
-
@scroll_position.y = 0 if @scroll_position.y > 0
|
350
|
-
@scroll_target_position.y = @scroll_position.y
|
351
|
-
|
352
|
-
return :handled
|
353
|
-
end
|
354
|
-
|
355
|
-
def scroll_page_down(sender, x, y)
|
356
|
-
return unless @style.scroll
|
357
|
-
|
358
|
-
@scroll_position.y -= height
|
359
|
-
@scroll_position.y = -max_scroll_height if @scroll_position.y < -max_scroll_height
|
360
|
-
@scroll_target_position.y = @scroll_position.y
|
361
|
-
|
362
|
-
return :handled
|
363
|
-
end
|
364
|
-
|
365
|
-
def scroll_top
|
366
|
-
@scroll_position.y
|
367
|
-
end
|
368
|
-
|
369
|
-
def scroll_top=(n)
|
370
|
-
n = 0 if n <= 0
|
371
|
-
@scroll_position.y = -n
|
372
|
-
|
373
|
-
if max_scroll_height.positive?
|
374
|
-
@scroll_position.y = -max_scroll_height if @scroll_position.y.abs > max_scroll_height
|
375
|
-
else
|
376
|
-
@scroll_position.y = 0
|
377
|
-
end
|
378
|
-
end
|
379
|
-
|
380
|
-
def value
|
381
|
-
@children.map(&:class).join(", ")
|
382
|
-
end
|
383
|
-
|
384
|
-
def to_s
|
385
|
-
"#{self.class} x=#{x} y=#{y} width=#{width} height=#{height} children=#{@children.size}"
|
386
|
-
end
|
387
|
-
|
388
|
-
def write_tree(indent = "", _index = 0)
|
389
|
-
puts self
|
390
|
-
|
391
|
-
indent += " "
|
392
|
-
@children.each_with_index do |child, i|
|
393
|
-
print "#{indent}#{i}: "
|
394
|
-
|
395
|
-
if child.is_a?(Container)
|
396
|
-
child.write_tree(indent)
|
397
|
-
else
|
398
|
-
puts child
|
399
|
-
end
|
400
|
-
end
|
401
|
-
end
|
402
|
-
end
|
403
|
-
end
|
404
|
-
end
|
1
|
+
module CyberarmEngine
|
2
|
+
class Element
|
3
|
+
class Container < Element
|
4
|
+
include Common
|
5
|
+
|
6
|
+
attr_accessor :stroke_color, :fill_color
|
7
|
+
attr_reader :children, :gui_state, :scroll_position, :scroll_target_position
|
8
|
+
|
9
|
+
def self.current_container
|
10
|
+
@@current_container
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.current_container=(container)
|
14
|
+
raise ArgumentError, "Expected container to an an instance of CyberarmEngine::Element::Container, got #{container.class}" unless container.is_a?(CyberarmEngine::Element::Container)
|
15
|
+
|
16
|
+
@@current_container = container
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(options = {}, block = nil)
|
20
|
+
@gui_state = options.delete(:gui_state)
|
21
|
+
super
|
22
|
+
|
23
|
+
@last_scroll_position = Vector.new(0, 0)
|
24
|
+
@scroll_position = Vector.new(0, 0)
|
25
|
+
@scroll_target_position = Vector.new(0, 0)
|
26
|
+
@scroll_chunk = 120
|
27
|
+
@scroll_speed = 40
|
28
|
+
|
29
|
+
@text_color = options[:color]
|
30
|
+
|
31
|
+
@children = []
|
32
|
+
|
33
|
+
event(:window_size_changed)
|
34
|
+
end
|
35
|
+
|
36
|
+
def build
|
37
|
+
@block.call(self) if @block
|
38
|
+
|
39
|
+
root.gui_state.request_recalculate_for(self)
|
40
|
+
end
|
41
|
+
|
42
|
+
def add(element)
|
43
|
+
@children << element
|
44
|
+
|
45
|
+
root.gui_state.request_recalculate_for(self)
|
46
|
+
end
|
47
|
+
|
48
|
+
def remove(element)
|
49
|
+
root.gui_state.request_recalculate_for(self) if @children.delete(element)
|
50
|
+
end
|
51
|
+
|
52
|
+
def append(&block)
|
53
|
+
old_container = CyberarmEngine::Element::Container.current_container
|
54
|
+
|
55
|
+
CyberarmEngine::Element::Container.current_container = self
|
56
|
+
block.call(self) if block
|
57
|
+
|
58
|
+
CyberarmEngine::Element::Container.current_container = old_container
|
59
|
+
|
60
|
+
root.gui_state.request_recalculate_for(self)
|
61
|
+
end
|
62
|
+
|
63
|
+
def clear(&block)
|
64
|
+
@children.clear
|
65
|
+
|
66
|
+
old_container = CyberarmEngine::Element::Container.current_container
|
67
|
+
|
68
|
+
CyberarmEngine::Element::Container.current_container = self
|
69
|
+
block.call(self) if block
|
70
|
+
|
71
|
+
CyberarmEngine::Element::Container.current_container = old_container
|
72
|
+
|
73
|
+
root.gui_state.request_recalculate_for(self)
|
74
|
+
end
|
75
|
+
|
76
|
+
def render
|
77
|
+
Gosu.clip_to(
|
78
|
+
@x + @style.border_thickness_left + @style.padding_left,
|
79
|
+
@y + @style.border_thickness_top + @style.padding_top,
|
80
|
+
content_width + 1,
|
81
|
+
content_height + 1
|
82
|
+
) do
|
83
|
+
Gosu.translate(@scroll_position.x, @scroll_position.y) do
|
84
|
+
@children.each(&:draw)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def debug_draw
|
90
|
+
super
|
91
|
+
|
92
|
+
@children.each do |child|
|
93
|
+
child.debug_draw
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def update
|
98
|
+
update_scroll if @style.scroll
|
99
|
+
@children.each(&:update)
|
100
|
+
end
|
101
|
+
|
102
|
+
def hit_element?(x, y)
|
103
|
+
return unless hit?(x, y)
|
104
|
+
|
105
|
+
# Offset child hit point by scroll position/offset
|
106
|
+
child_x = x - @scroll_position.x
|
107
|
+
child_y = y - @scroll_position.y
|
108
|
+
|
109
|
+
@children.reverse_each do |child|
|
110
|
+
next unless child.visible?
|
111
|
+
|
112
|
+
case child
|
113
|
+
when Container
|
114
|
+
if element = child.hit_element?(child_x, child_y)
|
115
|
+
return element
|
116
|
+
end
|
117
|
+
else
|
118
|
+
return child if child.hit?(child_x, child_y)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
self if hit?(x, y)
|
123
|
+
end
|
124
|
+
|
125
|
+
def update_child_element_visibity(child)
|
126
|
+
child.element_visible = child.x >= (@x - @scroll_position.x) - child.width && child.x <= (@x - @scroll_position.x) + width &&
|
127
|
+
child.y >= (@y - @scroll_position.y) - child.height && child.y <= (@y - @scroll_position.y) + height
|
128
|
+
end
|
129
|
+
|
130
|
+
def update_scroll
|
131
|
+
dt = window.dt.clamp(0.000001, 0.025)
|
132
|
+
@scroll_position.x += (((@scroll_target_position.x - @scroll_position.x) * (@scroll_speed / 4.0) * 0.98) * dt).round
|
133
|
+
@scroll_position.y += (((@scroll_target_position.y - @scroll_position.y) * (@scroll_speed / 4.0) * 0.98) * dt).round
|
134
|
+
|
135
|
+
# Scrolled PAST top
|
136
|
+
if @scroll_position.y > 0
|
137
|
+
@scroll_target_position.y = 0
|
138
|
+
|
139
|
+
# Scrolled PAST bottom
|
140
|
+
elsif @scroll_position.y < -max_scroll_height
|
141
|
+
@scroll_target_position.y = -max_scroll_height
|
142
|
+
end
|
143
|
+
|
144
|
+
if @last_scroll_position != @scroll_position
|
145
|
+
@children.each { |child| update_child_element_visibity(child) }
|
146
|
+
root.gui_state.request_repaint
|
147
|
+
end
|
148
|
+
|
149
|
+
@last_scroll_position.x = @scroll_position.x
|
150
|
+
@last_scroll_position.y = @scroll_position.y
|
151
|
+
end
|
152
|
+
|
153
|
+
def recalculate
|
154
|
+
@current_position = Vector.new(@style.margin_left + @style.padding_left, @style.margin_top + @style.padding_top)
|
155
|
+
|
156
|
+
return unless visible?
|
157
|
+
|
158
|
+
Stats.frame&.increment(:gui_recalculations)
|
159
|
+
|
160
|
+
# s = Gosu.milliseconds
|
161
|
+
|
162
|
+
stylize
|
163
|
+
layout
|
164
|
+
|
165
|
+
# Old sizes MUST be determined AFTER call to layout
|
166
|
+
old_width = width
|
167
|
+
old_height = height
|
168
|
+
|
169
|
+
@cached_scroll_width = nil
|
170
|
+
@cached_scroll_height = nil
|
171
|
+
|
172
|
+
if is_root?
|
173
|
+
@width = @style.width = window.width
|
174
|
+
@height = @style.height = window.height
|
175
|
+
else
|
176
|
+
@width = 0
|
177
|
+
@height = 0
|
178
|
+
|
179
|
+
_width = dimensional_size(@style.width, :width)
|
180
|
+
_height = dimensional_size(@style.height, :height)
|
181
|
+
|
182
|
+
@width = _width || (@children.map { |c| c.x + c.outer_width }.max || 0).floor
|
183
|
+
@height = _height || (@children.map { |c| c.y + c.outer_height }.max || 0).floor
|
184
|
+
end
|
185
|
+
|
186
|
+
# FIXME: Correctly handle alignment when element has siblings
|
187
|
+
# FIXME: Enable alignment for any element, not just containers
|
188
|
+
if @style.v_align
|
189
|
+
space = space_available_height
|
190
|
+
|
191
|
+
case @style.v_align
|
192
|
+
when :center
|
193
|
+
@y = parent.height / 2 - height / 2
|
194
|
+
when :bottom
|
195
|
+
@y = parent.height - height
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
if @style.h_align
|
200
|
+
space = space_available_width
|
201
|
+
|
202
|
+
case @style.h_align
|
203
|
+
when :center
|
204
|
+
@x = parent.width / 2 - width / 2
|
205
|
+
when :right
|
206
|
+
@x = parent.width - width
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# t = Gosu.milliseconds
|
211
|
+
# Move children to parent after positioning
|
212
|
+
@children.each do |child|
|
213
|
+
child.x += (@x + @style.border_thickness_left) - style.margin_left
|
214
|
+
child.y += (@y + @style.border_thickness_top) - style.margin_top
|
215
|
+
|
216
|
+
child.stylize
|
217
|
+
child.recalculate
|
218
|
+
child.reposition # TODO: Implement top,bottom,left,center, and right positioning
|
219
|
+
|
220
|
+
Stats.frame&.increment(:gui_recalculations)
|
221
|
+
|
222
|
+
update_child_element_visibity(child)
|
223
|
+
end
|
224
|
+
# puts "TOOK: #{Gosu.milliseconds - t}ms to recalculate #{self.class}:0x#{self.object_id.to_s(16)}'s #{@children.count} children"
|
225
|
+
|
226
|
+
update_background
|
227
|
+
|
228
|
+
# Fixes resized container scrolled past bottom
|
229
|
+
if old_height != @height
|
230
|
+
self.scroll_top = -@scroll_position.y
|
231
|
+
@scroll_target_position.y = @scroll_position.y
|
232
|
+
end
|
233
|
+
|
234
|
+
# Fixes resized container that is scrolled down from being stuck overscrolled when resized
|
235
|
+
if scroll_height < height
|
236
|
+
@scroll_target_position.y = 0
|
237
|
+
end
|
238
|
+
|
239
|
+
recalculate_if_size_changed
|
240
|
+
|
241
|
+
# puts "TOOK: #{Gosu.milliseconds - s}ms to recalculate #{self.class}:0x#{self.object_id.to_s(16)}"
|
242
|
+
end
|
243
|
+
|
244
|
+
def layout
|
245
|
+
raise "Not overridden"
|
246
|
+
end
|
247
|
+
|
248
|
+
def max_width
|
249
|
+
# _width = dimensional_size(@style.width, :width)
|
250
|
+
# if _width
|
251
|
+
# outer_width
|
252
|
+
# else
|
253
|
+
# window.width - (@parent ? @parent.style.margin_right + @style.margin_right : @style.margin_right)
|
254
|
+
# end
|
255
|
+
|
256
|
+
outer_width
|
257
|
+
end
|
258
|
+
|
259
|
+
def fits_on_line?(element) # Flow
|
260
|
+
@current_position.x + element.outer_width <= max_width &&
|
261
|
+
@current_position.x + element.outer_width <= window.width
|
262
|
+
end
|
263
|
+
|
264
|
+
def position_on_current_line(element) # Flow
|
265
|
+
element.x = element.style.margin_left + @current_position.x
|
266
|
+
element.y = element.style.margin_top + @current_position.y
|
267
|
+
|
268
|
+
@current_position.x += element.outer_width
|
269
|
+
end
|
270
|
+
|
271
|
+
def tallest_neighbor(querier, _y_position) # Flow
|
272
|
+
response = querier
|
273
|
+
@children.each do |child|
|
274
|
+
response = child if child.outer_height > response.outer_height
|
275
|
+
break if child == querier
|
276
|
+
end
|
277
|
+
|
278
|
+
response
|
279
|
+
end
|
280
|
+
|
281
|
+
def position_on_next_line(element) # Flow
|
282
|
+
@current_position.x = @style.margin_left + @style.padding_left
|
283
|
+
@current_position.y += tallest_neighbor(element, @current_position.y).outer_height
|
284
|
+
|
285
|
+
element.x = element.style.margin_left + @current_position.x
|
286
|
+
element.y = element.style.margin_top + @current_position.y
|
287
|
+
|
288
|
+
@current_position.x += element.outer_width
|
289
|
+
end
|
290
|
+
|
291
|
+
def move_to_next_line(element) # Stack
|
292
|
+
element.x = element.style.margin_left + @current_position.x
|
293
|
+
element.y = element.style.margin_top + @current_position.y
|
294
|
+
|
295
|
+
@current_position.y += element.outer_height
|
296
|
+
end
|
297
|
+
|
298
|
+
def mouse_wheel_up(sender, x, y)
|
299
|
+
return unless @style.scroll
|
300
|
+
|
301
|
+
# Allow overscrolling UP, only if one can scroll DOWN
|
302
|
+
if height < scroll_height
|
303
|
+
if @scroll_target_position.y > 0
|
304
|
+
@scroll_target_position.y = @scroll_chunk
|
305
|
+
else
|
306
|
+
@scroll_target_position.y += @scroll_chunk
|
307
|
+
end
|
308
|
+
|
309
|
+
return :handled
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
def mouse_wheel_down(sender, x, y)
|
314
|
+
return unless @style.scroll
|
315
|
+
|
316
|
+
return unless height < scroll_height
|
317
|
+
|
318
|
+
if @scroll_target_position.y > 0
|
319
|
+
@scroll_target_position.y = -@scroll_chunk
|
320
|
+
else
|
321
|
+
@scroll_target_position.y -= @scroll_chunk
|
322
|
+
end
|
323
|
+
|
324
|
+
return :handled
|
325
|
+
end
|
326
|
+
|
327
|
+
def scroll_jump_to_top(sender, x, y)
|
328
|
+
return unless @style.scroll
|
329
|
+
|
330
|
+
@scroll_position.y = 0
|
331
|
+
@scroll_target_position.y = 0
|
332
|
+
|
333
|
+
return :handled
|
334
|
+
end
|
335
|
+
|
336
|
+
def scroll_jump_to_end(sender, x, y)
|
337
|
+
return unless @style.scroll
|
338
|
+
|
339
|
+
@scroll_position.y = -max_scroll_height
|
340
|
+
@scroll_target_position.y = -max_scroll_height
|
341
|
+
|
342
|
+
return :handled
|
343
|
+
end
|
344
|
+
|
345
|
+
def scroll_page_up(sender, x, y)
|
346
|
+
return unless @style.scroll
|
347
|
+
|
348
|
+
@scroll_position.y += height
|
349
|
+
@scroll_position.y = 0 if @scroll_position.y > 0
|
350
|
+
@scroll_target_position.y = @scroll_position.y
|
351
|
+
|
352
|
+
return :handled
|
353
|
+
end
|
354
|
+
|
355
|
+
def scroll_page_down(sender, x, y)
|
356
|
+
return unless @style.scroll
|
357
|
+
|
358
|
+
@scroll_position.y -= height
|
359
|
+
@scroll_position.y = -max_scroll_height if @scroll_position.y < -max_scroll_height
|
360
|
+
@scroll_target_position.y = @scroll_position.y
|
361
|
+
|
362
|
+
return :handled
|
363
|
+
end
|
364
|
+
|
365
|
+
def scroll_top
|
366
|
+
@scroll_position.y
|
367
|
+
end
|
368
|
+
|
369
|
+
def scroll_top=(n)
|
370
|
+
n = 0 if n <= 0
|
371
|
+
@scroll_position.y = -n
|
372
|
+
|
373
|
+
if max_scroll_height.positive?
|
374
|
+
@scroll_position.y = -max_scroll_height if @scroll_position.y.abs > max_scroll_height
|
375
|
+
else
|
376
|
+
@scroll_position.y = 0
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
def value
|
381
|
+
@children.map(&:class).join(", ")
|
382
|
+
end
|
383
|
+
|
384
|
+
def to_s
|
385
|
+
"#{self.class} x=#{x} y=#{y} width=#{width} height=#{height} children=#{@children.size}"
|
386
|
+
end
|
387
|
+
|
388
|
+
def write_tree(indent = "", _index = 0)
|
389
|
+
puts self
|
390
|
+
|
391
|
+
indent += " "
|
392
|
+
@children.each_with_index do |child, i|
|
393
|
+
print "#{indent}#{i}: "
|
394
|
+
|
395
|
+
if child.is_a?(Container)
|
396
|
+
child.write_tree(indent)
|
397
|
+
else
|
398
|
+
puts child
|
399
|
+
end
|
400
|
+
end
|
401
|
+
end
|
402
|
+
end
|
403
|
+
end
|
404
|
+
end
|