cyberarm_engine 0.25.0 → 0.25.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.
Files changed (94) 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 +25 -25
  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 -115
  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 +158 -158
  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 +131 -131
  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 +111 -111
  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/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 -216
  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 -52
  48. data/lib/cyberarm_engine/opengl/orthographic_camera.rb +46 -46
  49. data/lib/cyberarm_engine/opengl/perspective_camera.rb +41 -41
  50. data/lib/cyberarm_engine/opengl/renderer/bounding_box_renderer.rb +249 -249
  51. data/lib/cyberarm_engine/opengl/renderer/g_buffer.rb +167 -167
  52. data/lib/cyberarm_engine/opengl/renderer/opengl_renderer.rb +307 -307
  53. data/lib/cyberarm_engine/opengl/renderer/renderer.rb +33 -33
  54. data/lib/cyberarm_engine/opengl/shader.rb +408 -408
  55. data/lib/cyberarm_engine/opengl/texture.rb +69 -69
  56. data/lib/cyberarm_engine/opengl.rb +53 -53
  57. data/lib/cyberarm_engine/ray.rb +56 -56
  58. data/lib/cyberarm_engine/result.rb +20 -0
  59. data/lib/cyberarm_engine/stats.rb +200 -200
  60. data/lib/cyberarm_engine/text.rb +260 -260
  61. data/lib/cyberarm_engine/timer.rb +23 -23
  62. data/lib/cyberarm_engine/transform.rb +296 -296
  63. data/lib/cyberarm_engine/trees/aabb_node.rb +126 -126
  64. data/lib/cyberarm_engine/trees/aabb_tree.rb +55 -55
  65. data/lib/cyberarm_engine/trees/aabb_tree_debug.rb +29 -29
  66. data/lib/cyberarm_engine/ui/border_canvas.rb +102 -102
  67. data/lib/cyberarm_engine/ui/dsl.rb +142 -142
  68. data/lib/cyberarm_engine/ui/element.rb +662 -662
  69. data/lib/cyberarm_engine/ui/elements/button.rb +100 -100
  70. data/lib/cyberarm_engine/ui/elements/check_box.rb +54 -54
  71. data/lib/cyberarm_engine/ui/elements/container.rb +407 -407
  72. data/lib/cyberarm_engine/ui/elements/edit_box.rb +179 -179
  73. data/lib/cyberarm_engine/ui/elements/edit_line.rb +297 -297
  74. data/lib/cyberarm_engine/ui/elements/flow.rb +15 -15
  75. data/lib/cyberarm_engine/ui/elements/image.rb +72 -72
  76. data/lib/cyberarm_engine/ui/elements/list_box.rb +79 -79
  77. data/lib/cyberarm_engine/ui/elements/menu.rb +27 -27
  78. data/lib/cyberarm_engine/ui/elements/menu_item.rb +6 -6
  79. data/lib/cyberarm_engine/ui/elements/progress.rb +93 -93
  80. data/lib/cyberarm_engine/ui/elements/radio.rb +6 -6
  81. data/lib/cyberarm_engine/ui/elements/slider.rb +107 -107
  82. data/lib/cyberarm_engine/ui/elements/stack.rb +11 -11
  83. data/lib/cyberarm_engine/ui/elements/text_block.rb +222 -222
  84. data/lib/cyberarm_engine/ui/elements/toggle_button.rb +67 -67
  85. data/lib/cyberarm_engine/ui/event.rb +54 -54
  86. data/lib/cyberarm_engine/ui/gui_state.rb +326 -326
  87. data/lib/cyberarm_engine/ui/style.rb +61 -61
  88. data/lib/cyberarm_engine/ui/theme.rb +225 -225
  89. data/lib/cyberarm_engine/vector.rb +312 -312
  90. data/lib/cyberarm_engine/version.rb +4 -4
  91. data/lib/cyberarm_engine/window.rb +195 -195
  92. data/lib/cyberarm_engine.rb +77 -76
  93. data/mrbgem.rake +29 -29
  94. metadata +4 -3
@@ -1,326 +1,326 @@
1
- module CyberarmEngine
2
- class GuiState < GameState
3
- include Common
4
- include DSL
5
-
6
- def initialize(options = {})
7
- @options = options
8
- @game_objects = []
9
- @global_pause = false
10
-
11
- @down_keys = {}
12
-
13
- @root_container = Element::Stack.new(gui_state: self)
14
- @game_objects << @root_container
15
- CyberarmEngine::Element::Container.current_container = @root_container
16
-
17
- @active_width = window.width
18
- @active_height = window.height
19
-
20
- @menu = nil
21
- @focus = nil
22
- @mouse_over = nil
23
- @mouse_down_on = {}
24
- @mouse_down_position = {}
25
- @last_mouse_pos = nil
26
- @dragging_element = nil
27
- @pending_recalculate_request = false
28
- @pending_element_recalculate_requests = []
29
-
30
- @needs_repaint = false
31
-
32
- @menu = nil
33
- @min_drag_distance = 0
34
- @mouse_pos = Vector.new
35
- end
36
-
37
- def post_setup
38
- @tip = Element::ToolTip.new("", parent: @root_container, z: Float::INFINITY, theme: current_theme)
39
- end
40
-
41
- def menu
42
- @menu
43
- end
44
-
45
- # throws :blur event to focused element and sets GuiState focused element
46
- # Does NOT throw :focus event at element or set element as focused
47
- def focus=(element)
48
- @focus.publish(:blur) if @focus && element && @focus != element
49
- @focus = element
50
- end
51
-
52
- def focused
53
- @focus
54
- end
55
-
56
- def draw
57
- # t = Gosu.milliseconds
58
- # report_recalculate_time = @pending_recalculate_request || @pending_element_recalculate_requests.size.positive?
59
-
60
- StackProf.start(mode: :wall) if RUBY_ENGINE != "mruby" && defined?(StackProf)
61
- Stats.frame.start_timing(:gui_element_recalculate_requests)
62
-
63
- # puts "PENDING REQUESTS: #{@pending_element_recalculate_requests.size}" if @pending_element_recalculate_requests.size.positive?
64
- @pending_element_recalculate_requests.shift(&:recalculate)
65
-
66
- Stats.frame.end_timing(:gui_element_recalculate_requests)
67
-
68
- Stats.frame.start_timing(:gui_recalculate)
69
-
70
- while(@pending_recalculate_request)
71
- @pending_recalculate_request = false
72
-
73
- @root_container.recalculate
74
- end
75
-
76
- StackProf.stop if RUBY_ENGINE != "mruby" && defined?(StackProf)
77
- Stats.frame.end_timing(:gui_recalculate)
78
- # puts "TOOK: #{Gosu.milliseconds - t}ms to recalculate #{self.class}:0x#{object_id.to_s(16)}" if report_recalculate_time && Gosu.milliseconds - t > 0
79
-
80
- super
81
-
82
- if @menu
83
- Gosu.flush
84
- @menu.draw
85
- end
86
-
87
- if @tip && @tip.value.length.positive?
88
- Gosu.flush
89
-
90
- @tip.draw
91
- end
92
-
93
- if CyberarmEngine.const_defined?("GUI_DEBUG")
94
- Gosu.flush
95
-
96
- @root_container.debug_draw
97
- end
98
-
99
- @needs_repaint = false
100
- end
101
-
102
- def needs_repaint?
103
- @needs_repaint
104
- end
105
-
106
- def update
107
- if @pending_focus_request
108
- @pending_focus_request = false
109
-
110
- self.focus = @pending_focus_element
111
- @pending_focus_element.publish(:focus)
112
- end
113
-
114
- @menu&.update
115
-
116
- super
117
-
118
- if @active_width != window.width || @active_height != window.height
119
- request_recalculate
120
- @root_container.publish(:window_size_changed)
121
- end
122
-
123
- @active_width = window.width
124
- @active_height = window.height
125
-
126
- return unless window.has_focus?
127
- return unless window.current_state == self
128
-
129
- new_mouse_over = @menu.hit_element?(window.mouse_x, window.mouse_y) if @menu
130
- new_mouse_over ||= @root_container.hit_element?(window.mouse_x, window.mouse_y)
131
-
132
- if new_mouse_over
133
- new_mouse_over.publish(:enter) if new_mouse_over != @mouse_over
134
- new_mouse_over.publish(:hover)
135
- # puts "#{new_mouse_over.class}[#{new_mouse_over.value}]: #{new_mouse_over.x}:#{new_mouse_over.y} #{new_mouse_over.width}:#{new_mouse_over.height}" if new_mouse_over != @mouse_over
136
- end
137
- @mouse_over.publish(:leave) if @mouse_over && new_mouse_over != @mouse_over
138
- @mouse_over = new_mouse_over
139
-
140
- redirect_holding_mouse_button(:left) if @mouse_over && Gosu.button_down?(Gosu::MS_LEFT)
141
- redirect_holding_mouse_button(:middle) if @mouse_over && Gosu.button_down?(Gosu::MS_MIDDLE)
142
- redirect_holding_mouse_button(:right) if @mouse_over && Gosu.button_down?(Gosu::MS_RIGHT)
143
-
144
- if Vector.new(window.mouse_x, window.mouse_y) == @last_mouse_pos
145
- if @mouse_over && (Gosu.milliseconds - @mouse_moved_at) > tool_tip_delay
146
- @tip.value = @mouse_over.tip if @mouse_over
147
- @tip.x = window.mouse_x
148
- @tip.x = 0 if @tip.x < 0
149
- @tip.x = window.width - @tip.width if @tip.x + @tip.width > window.width
150
- @tip.y = window.mouse_y - (@tip.height + 5)
151
- @tip.y = 0 if @tip.y < 0
152
- @tip.y = window.height - @tip.height if @tip.y + @tip.height > window.height
153
- @tip.update
154
- @tip.recalculate
155
- else
156
- @tip.value = ""
157
- end
158
- else
159
- @mouse_moved_at = Gosu.milliseconds
160
- end
161
-
162
- @last_mouse_pos = Vector.new(window.mouse_x, window.mouse_y)
163
- @mouse_pos = @last_mouse_pos.clone
164
- end
165
-
166
- def button_down(id)
167
- super
168
-
169
- case id
170
- when Gosu::MS_LEFT
171
- redirect_mouse_button(:left)
172
- when Gosu::MS_MIDDLE
173
- redirect_mouse_button(:middle)
174
- when Gosu::MS_RIGHT
175
- redirect_mouse_button(:right)
176
- when Gosu::KB_F5
177
- request_recalculate
178
- end
179
-
180
- @focus.button_down(id) if @focus.respond_to?(:button_down)
181
- end
182
-
183
- def button_up(id)
184
- super
185
-
186
- case id
187
- when Gosu::MS_LEFT
188
- redirect_released_mouse_button(:left)
189
- when Gosu::MS_MIDDLE
190
- redirect_released_mouse_button(:middle)
191
- when Gosu::MS_RIGHT
192
- redirect_released_mouse_button(:right)
193
- when Gosu::MS_WHEEL_UP
194
- redirect_mouse_wheel(:up)
195
- when Gosu::MS_WHEEL_DOWN
196
- redirect_mouse_wheel(:down)
197
- when Gosu::KB_HOME
198
- redirect_scroll_jump_to(:top)
199
- when Gosu::KB_END
200
- redirect_scroll_jump_to(:end)
201
- when Gosu::KB_PAGE_UP
202
- redirect_scroll_page(:up)
203
- when Gosu::KB_PAGE_DOWN
204
- redirect_scroll_page(:down)
205
- end
206
-
207
- @focus.button_up(id) if @focus.respond_to?(:button_up)
208
-
209
- # Prevents menu from popping back up if the listbox is clicked to hide it.
210
- @hid_menu_for = nil
211
- end
212
-
213
- def tool_tip_delay
214
- @tip.style.delay || 250 # ms
215
- end
216
-
217
- def redirect_mouse_button(button)
218
- hide_menu unless @menu && (@menu == @mouse_over) || (@mouse_over&.parent == @menu)
219
-
220
- if @focus && @mouse_over != @focus
221
- @focus.publish(:blur)
222
- @focus = nil
223
- end
224
-
225
- if @mouse_over && @hid_menu_for != @mouse_over
226
- @mouse_down_position[button] = Vector.new(window.mouse_x, window.mouse_y)
227
- @mouse_down_on[button] = @mouse_over
228
-
229
- @mouse_over.publish(:"#{button}_mouse_button", window.mouse_x, window.mouse_y)
230
- else
231
- @mouse_down_position[button] = nil
232
- @mouse_down_on[button] = nil
233
- end
234
- end
235
-
236
- def redirect_released_mouse_button(button)
237
- hide_menu if @menu && (@menu == @mouse_over) || (@mouse_over&.parent == @menu)
238
-
239
- if @mouse_over && @hid_menu_for != @mouse_over
240
- @mouse_over.publish(:"released_#{button}_mouse_button", window.mouse_x, window.mouse_y)
241
- if @mouse_over == @mouse_down_on[button]
242
- @mouse_over.publish(:"clicked_#{button}_mouse_button", window.mouse_x,
243
- window.mouse_y)
244
- end
245
- end
246
-
247
- if @dragging_element
248
- @dragging_element.publish(:end_drag, window.mouse_x, window.mouse_y, button)
249
- @dragging_element = nil
250
- end
251
-
252
- @mouse_down_position[button] = nil
253
- @mouse_down_on[button] = nil
254
- end
255
-
256
- def redirect_holding_mouse_button(button)
257
- if !@dragging_element && @mouse_down_on[button] && @mouse_down_on[button].draggable?(button) && @mouse_pos.distance(@mouse_down_position[button]) > @min_drag_distance
258
- @dragging_element = @mouse_down_on[button]
259
- @dragging_element.publish(:begin_drag, window.mouse_x, window.mouse_y, button)
260
- end
261
-
262
- if @dragging_element
263
- @dragging_element.publish(:drag_update, window.mouse_x, window.mouse_y, button) if @dragging_element
264
- elsif @mouse_over
265
- @mouse_over.publish(:"holding_#{button}_mouse_button", window.mouse_x, window.mouse_y)
266
- end
267
- end
268
-
269
- def redirect_mouse_wheel(button)
270
- @mouse_over.publish(:"mouse_wheel_#{button}", window.mouse_x, window.mouse_y) if (@mouse_over && !@menu) || (@mouse_over && @mouse_over == @menu)
271
- end
272
-
273
- def redirect_scroll_jump_to(edge)
274
- @mouse_over.publish(:"scroll_jump_to_#{edge}", window.mouse_x, window.mouse_y) if (@mouse_over && !@menu) || (@mouse_over && @mouse_over == @menu)
275
- end
276
-
277
- def redirect_scroll_page(edge)
278
- @mouse_over.publish(:"scroll_page_#{edge}", window.mouse_x, window.mouse_y) if (@mouse_over && !@menu) || (@mouse_over && @mouse_over == @menu)
279
- end
280
-
281
- # Schedule a full GUI recalculation on next update
282
- def request_recalculate
283
- @pending_recalculate_request = true
284
- end
285
-
286
- def request_recalculate_for(element)
287
- # element is already queued
288
- return if @pending_element_recalculate_requests.detect { |e| e == element }
289
-
290
- @pending_element_recalculate_requests << element
291
- end
292
-
293
- def request_focus(element)
294
- @pending_focus_request = true
295
- @pending_focus_element = element
296
- end
297
-
298
- def request_repaint
299
- # puts caller[0..4]
300
- # puts
301
- @needs_repaint = true
302
- end
303
-
304
- def show_menu(list_box)
305
- @menu = list_box
306
- end
307
-
308
- def hide_menu
309
- return unless @menu
310
-
311
- request_repaint
312
-
313
- @hid_menu_for = @menu.parent
314
- @menu = nil
315
- end
316
-
317
- def to_s
318
- # "#{self.class} children=#{@children.map { |c| c.to_s }}"
319
- @root_container.to_s
320
- end
321
-
322
- def inspect
323
- to_s
324
- end
325
- end
326
- end
1
+ module CyberarmEngine
2
+ class GuiState < GameState
3
+ include Common
4
+ include DSL
5
+
6
+ def initialize(options = {})
7
+ @options = options
8
+ @game_objects = []
9
+ @global_pause = false
10
+
11
+ @down_keys = {}
12
+
13
+ @root_container = Element::Stack.new(gui_state: self)
14
+ @game_objects << @root_container
15
+ CyberarmEngine::Element::Container.current_container = @root_container
16
+
17
+ @active_width = window.width
18
+ @active_height = window.height
19
+
20
+ @menu = nil
21
+ @focus = nil
22
+ @mouse_over = nil
23
+ @mouse_down_on = {}
24
+ @mouse_down_position = {}
25
+ @last_mouse_pos = nil
26
+ @dragging_element = nil
27
+ @pending_recalculate_request = false
28
+ @pending_element_recalculate_requests = []
29
+
30
+ @needs_repaint = false
31
+
32
+ @menu = nil
33
+ @min_drag_distance = 0
34
+ @mouse_pos = Vector.new
35
+ end
36
+
37
+ def post_setup
38
+ @tip = Element::ToolTip.new("", parent: @root_container, z: Float::INFINITY, theme: current_theme)
39
+ end
40
+
41
+ def menu
42
+ @menu
43
+ end
44
+
45
+ # throws :blur event to focused element and sets GuiState focused element
46
+ # Does NOT throw :focus event at element or set element as focused
47
+ def focus=(element)
48
+ @focus.publish(:blur) if @focus && element && @focus != element
49
+ @focus = element
50
+ end
51
+
52
+ def focused
53
+ @focus
54
+ end
55
+
56
+ def draw
57
+ # t = Gosu.milliseconds
58
+ # report_recalculate_time = @pending_recalculate_request || @pending_element_recalculate_requests.size.positive?
59
+
60
+ StackProf.start(mode: :wall) if RUBY_ENGINE != "mruby" && defined?(StackProf)
61
+ Stats.frame.start_timing(:gui_element_recalculate_requests)
62
+
63
+ # puts "PENDING REQUESTS: #{@pending_element_recalculate_requests.size}" if @pending_element_recalculate_requests.size.positive?
64
+ @pending_element_recalculate_requests.shift(&:recalculate)
65
+
66
+ Stats.frame.end_timing(:gui_element_recalculate_requests)
67
+
68
+ Stats.frame.start_timing(:gui_recalculate)
69
+
70
+ while(@pending_recalculate_request)
71
+ @pending_recalculate_request = false
72
+
73
+ @root_container.recalculate
74
+ end
75
+
76
+ StackProf.stop if RUBY_ENGINE != "mruby" && defined?(StackProf)
77
+ Stats.frame.end_timing(:gui_recalculate)
78
+ # puts "TOOK: #{Gosu.milliseconds - t}ms to recalculate #{self.class}:0x#{object_id.to_s(16)}" if report_recalculate_time && Gosu.milliseconds - t > 0
79
+
80
+ super
81
+
82
+ if @menu
83
+ Gosu.flush
84
+ @menu.draw
85
+ end
86
+
87
+ if @tip && @tip.value.length.positive?
88
+ Gosu.flush
89
+
90
+ @tip.draw
91
+ end
92
+
93
+ if CyberarmEngine.const_defined?("GUI_DEBUG")
94
+ Gosu.flush
95
+
96
+ @root_container.debug_draw
97
+ end
98
+
99
+ @needs_repaint = false
100
+ end
101
+
102
+ def needs_repaint?
103
+ @needs_repaint
104
+ end
105
+
106
+ def update
107
+ if @pending_focus_request
108
+ @pending_focus_request = false
109
+
110
+ self.focus = @pending_focus_element
111
+ @pending_focus_element.publish(:focus)
112
+ end
113
+
114
+ @menu&.update
115
+
116
+ super
117
+
118
+ if @active_width != window.width || @active_height != window.height
119
+ request_recalculate
120
+ @root_container.publish(:window_size_changed)
121
+ end
122
+
123
+ @active_width = window.width
124
+ @active_height = window.height
125
+
126
+ return unless window.has_focus?
127
+ return unless window.current_state == self
128
+
129
+ new_mouse_over = @menu.hit_element?(window.mouse_x, window.mouse_y) if @menu
130
+ new_mouse_over ||= @root_container.hit_element?(window.mouse_x, window.mouse_y)
131
+
132
+ if new_mouse_over
133
+ new_mouse_over.publish(:enter) if new_mouse_over != @mouse_over
134
+ new_mouse_over.publish(:hover)
135
+ # puts "#{new_mouse_over.class}[#{new_mouse_over.value}]: #{new_mouse_over.x}:#{new_mouse_over.y} #{new_mouse_over.width}:#{new_mouse_over.height}" if new_mouse_over != @mouse_over
136
+ end
137
+ @mouse_over.publish(:leave) if @mouse_over && new_mouse_over != @mouse_over
138
+ @mouse_over = new_mouse_over
139
+
140
+ redirect_holding_mouse_button(:left) if @mouse_over && Gosu.button_down?(Gosu::MS_LEFT)
141
+ redirect_holding_mouse_button(:middle) if @mouse_over && Gosu.button_down?(Gosu::MS_MIDDLE)
142
+ redirect_holding_mouse_button(:right) if @mouse_over && Gosu.button_down?(Gosu::MS_RIGHT)
143
+
144
+ if Vector.new(window.mouse_x, window.mouse_y) == @last_mouse_pos
145
+ if @mouse_over && (Gosu.milliseconds - @mouse_moved_at) > tool_tip_delay
146
+ @tip.value = @mouse_over.tip if @mouse_over
147
+ @tip.x = window.mouse_x
148
+ @tip.x = 0 if @tip.x < 0
149
+ @tip.x = window.width - @tip.width if @tip.x + @tip.width > window.width
150
+ @tip.y = window.mouse_y - (@tip.height + 5)
151
+ @tip.y = 0 if @tip.y < 0
152
+ @tip.y = window.height - @tip.height if @tip.y + @tip.height > window.height
153
+ @tip.update
154
+ @tip.recalculate
155
+ else
156
+ @tip.value = ""
157
+ end
158
+ else
159
+ @mouse_moved_at = Gosu.milliseconds
160
+ end
161
+
162
+ @last_mouse_pos = Vector.new(window.mouse_x, window.mouse_y)
163
+ @mouse_pos = @last_mouse_pos.clone
164
+ end
165
+
166
+ def button_down(id)
167
+ super
168
+
169
+ case id
170
+ when Gosu::MS_LEFT
171
+ redirect_mouse_button(:left)
172
+ when Gosu::MS_MIDDLE
173
+ redirect_mouse_button(:middle)
174
+ when Gosu::MS_RIGHT
175
+ redirect_mouse_button(:right)
176
+ when Gosu::KB_F5
177
+ request_recalculate
178
+ end
179
+
180
+ @focus.button_down(id) if @focus.respond_to?(:button_down)
181
+ end
182
+
183
+ def button_up(id)
184
+ super
185
+
186
+ case id
187
+ when Gosu::MS_LEFT
188
+ redirect_released_mouse_button(:left)
189
+ when Gosu::MS_MIDDLE
190
+ redirect_released_mouse_button(:middle)
191
+ when Gosu::MS_RIGHT
192
+ redirect_released_mouse_button(:right)
193
+ when Gosu::MS_WHEEL_UP
194
+ redirect_mouse_wheel(:up)
195
+ when Gosu::MS_WHEEL_DOWN
196
+ redirect_mouse_wheel(:down)
197
+ when Gosu::KB_HOME
198
+ redirect_scroll_jump_to(:top)
199
+ when Gosu::KB_END
200
+ redirect_scroll_jump_to(:end)
201
+ when Gosu::KB_PAGE_UP
202
+ redirect_scroll_page(:up)
203
+ when Gosu::KB_PAGE_DOWN
204
+ redirect_scroll_page(:down)
205
+ end
206
+
207
+ @focus.button_up(id) if @focus.respond_to?(:button_up)
208
+
209
+ # Prevents menu from popping back up if the listbox is clicked to hide it.
210
+ @hid_menu_for = nil
211
+ end
212
+
213
+ def tool_tip_delay
214
+ @tip.style.delay || 250 # ms
215
+ end
216
+
217
+ def redirect_mouse_button(button)
218
+ hide_menu unless @menu && (@menu == @mouse_over) || (@mouse_over&.parent == @menu)
219
+
220
+ if @focus && @mouse_over != @focus
221
+ @focus.publish(:blur)
222
+ @focus = nil
223
+ end
224
+
225
+ if @mouse_over && @hid_menu_for != @mouse_over
226
+ @mouse_down_position[button] = Vector.new(window.mouse_x, window.mouse_y)
227
+ @mouse_down_on[button] = @mouse_over
228
+
229
+ @mouse_over.publish(:"#{button}_mouse_button", window.mouse_x, window.mouse_y)
230
+ else
231
+ @mouse_down_position[button] = nil
232
+ @mouse_down_on[button] = nil
233
+ end
234
+ end
235
+
236
+ def redirect_released_mouse_button(button)
237
+ hide_menu if @menu && (@menu == @mouse_over) || (@mouse_over&.parent == @menu)
238
+
239
+ if @mouse_over && @hid_menu_for != @mouse_over
240
+ @mouse_over.publish(:"released_#{button}_mouse_button", window.mouse_x, window.mouse_y)
241
+ if @mouse_over == @mouse_down_on[button]
242
+ @mouse_over.publish(:"clicked_#{button}_mouse_button", window.mouse_x,
243
+ window.mouse_y)
244
+ end
245
+ end
246
+
247
+ if @dragging_element
248
+ @dragging_element.publish(:end_drag, window.mouse_x, window.mouse_y, button)
249
+ @dragging_element = nil
250
+ end
251
+
252
+ @mouse_down_position[button] = nil
253
+ @mouse_down_on[button] = nil
254
+ end
255
+
256
+ def redirect_holding_mouse_button(button)
257
+ if !@dragging_element && @mouse_down_on[button] && @mouse_down_on[button].draggable?(button) && @mouse_pos.distance(@mouse_down_position[button]) > @min_drag_distance
258
+ @dragging_element = @mouse_down_on[button]
259
+ @dragging_element.publish(:begin_drag, window.mouse_x, window.mouse_y, button)
260
+ end
261
+
262
+ if @dragging_element
263
+ @dragging_element.publish(:drag_update, window.mouse_x, window.mouse_y, button) if @dragging_element
264
+ elsif @mouse_over
265
+ @mouse_over.publish(:"holding_#{button}_mouse_button", window.mouse_x, window.mouse_y)
266
+ end
267
+ end
268
+
269
+ def redirect_mouse_wheel(button)
270
+ @mouse_over.publish(:"mouse_wheel_#{button}", window.mouse_x, window.mouse_y) if (@mouse_over && !@menu) || (@mouse_over && @mouse_over == @menu)
271
+ end
272
+
273
+ def redirect_scroll_jump_to(edge)
274
+ @mouse_over.publish(:"scroll_jump_to_#{edge}", window.mouse_x, window.mouse_y) if (@mouse_over && !@menu) || (@mouse_over && @mouse_over == @menu)
275
+ end
276
+
277
+ def redirect_scroll_page(edge)
278
+ @mouse_over.publish(:"scroll_page_#{edge}", window.mouse_x, window.mouse_y) if (@mouse_over && !@menu) || (@mouse_over && @mouse_over == @menu)
279
+ end
280
+
281
+ # Schedule a full GUI recalculation on next update
282
+ def request_recalculate
283
+ @pending_recalculate_request = true
284
+ end
285
+
286
+ def request_recalculate_for(element)
287
+ # element is already queued
288
+ return if @pending_element_recalculate_requests.detect { |e| e == element }
289
+
290
+ @pending_element_recalculate_requests << element
291
+ end
292
+
293
+ def request_focus(element)
294
+ @pending_focus_request = true
295
+ @pending_focus_element = element
296
+ end
297
+
298
+ def request_repaint
299
+ # puts caller[0..4]
300
+ # puts
301
+ @needs_repaint = true
302
+ end
303
+
304
+ def show_menu(list_box)
305
+ @menu = list_box
306
+ end
307
+
308
+ def hide_menu
309
+ return unless @menu
310
+
311
+ request_repaint
312
+
313
+ @hid_menu_for = @menu.parent
314
+ @menu = nil
315
+ end
316
+
317
+ def to_s
318
+ # "#{self.class} children=#{@children.map { |c| c.to_s }}"
319
+ @root_container.to_s
320
+ end
321
+
322
+ def inspect
323
+ to_s
324
+ end
325
+ end
326
+ end