cyberarm_engine 0.13.0 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +8 -8
  3. data/.rubocop.yml +8 -0
  4. data/.travis.yml +5 -5
  5. data/Gemfile +6 -6
  6. data/LICENSE.txt +21 -21
  7. data/README.md +73 -43
  8. data/Rakefile +10 -10
  9. data/assets/textures/default.png +0 -0
  10. data/bin/console +14 -14
  11. data/bin/setup +8 -8
  12. data/cyberarm_engine.gemspec +39 -36
  13. data/lib/cyberarm_engine.rb +64 -47
  14. data/lib/cyberarm_engine/animator.rb +56 -54
  15. data/lib/cyberarm_engine/background.rb +179 -175
  16. data/lib/cyberarm_engine/background_nine_slice.rb +125 -0
  17. data/lib/cyberarm_engine/bounding_box.rb +150 -150
  18. data/lib/cyberarm_engine/cache.rb +4 -0
  19. data/lib/cyberarm_engine/cache/download_manager.rb +121 -0
  20. data/lib/cyberarm_engine/common.rb +96 -96
  21. data/lib/cyberarm_engine/config_file.rb +46 -0
  22. data/lib/cyberarm_engine/game_object.rb +248 -257
  23. data/lib/cyberarm_engine/game_state.rb +92 -89
  24. data/lib/cyberarm_engine/model.rb +207 -0
  25. data/lib/cyberarm_engine/model/material.rb +21 -0
  26. data/lib/cyberarm_engine/model/model_object.rb +131 -0
  27. data/lib/cyberarm_engine/model/parser.rb +74 -0
  28. data/lib/cyberarm_engine/model/parsers/collada_parser.rb +138 -0
  29. data/lib/cyberarm_engine/model/parsers/wavefront_parser.rb +154 -0
  30. data/lib/cyberarm_engine/model_cache.rb +31 -0
  31. data/lib/cyberarm_engine/opengl.rb +28 -0
  32. data/lib/cyberarm_engine/opengl/light.rb +50 -0
  33. data/lib/cyberarm_engine/opengl/orthographic_camera.rb +46 -0
  34. data/lib/cyberarm_engine/opengl/perspective_camera.rb +38 -0
  35. data/lib/cyberarm_engine/opengl/renderer/bounding_box_renderer.rb +249 -0
  36. data/lib/cyberarm_engine/opengl/renderer/g_buffer.rb +164 -0
  37. data/lib/cyberarm_engine/opengl/renderer/opengl_renderer.rb +289 -0
  38. data/lib/cyberarm_engine/opengl/renderer/renderer.rb +22 -0
  39. data/lib/cyberarm_engine/opengl/shader.rb +406 -0
  40. data/lib/cyberarm_engine/opengl/texture.rb +69 -0
  41. data/lib/cyberarm_engine/ray.rb +56 -56
  42. data/lib/cyberarm_engine/stats.rb +21 -0
  43. data/lib/cyberarm_engine/text.rb +160 -146
  44. data/lib/cyberarm_engine/timer.rb +23 -23
  45. data/lib/cyberarm_engine/transform.rb +296 -273
  46. data/lib/cyberarm_engine/ui/border_canvas.rb +102 -101
  47. data/lib/cyberarm_engine/ui/dsl.rb +138 -99
  48. data/lib/cyberarm_engine/ui/element.rb +315 -276
  49. data/lib/cyberarm_engine/ui/elements/button.rb +160 -67
  50. data/lib/cyberarm_engine/ui/elements/check_box.rb +51 -59
  51. data/lib/cyberarm_engine/ui/elements/container.rb +256 -176
  52. data/lib/cyberarm_engine/ui/elements/edit_box.rb +179 -0
  53. data/lib/cyberarm_engine/ui/elements/edit_line.rb +262 -172
  54. data/lib/cyberarm_engine/ui/elements/flow.rb +15 -17
  55. data/lib/cyberarm_engine/ui/elements/image.rb +72 -52
  56. data/lib/cyberarm_engine/ui/elements/label.rb +156 -50
  57. data/lib/cyberarm_engine/ui/elements/list_box.rb +82 -0
  58. data/lib/cyberarm_engine/ui/elements/progress.rb +51 -50
  59. data/lib/cyberarm_engine/ui/elements/radio.rb +6 -0
  60. data/lib/cyberarm_engine/ui/elements/slider.rb +104 -0
  61. data/lib/cyberarm_engine/ui/elements/stack.rb +11 -13
  62. data/lib/cyberarm_engine/ui/elements/text_block.rb +156 -0
  63. data/lib/cyberarm_engine/ui/elements/toggle_button.rb +65 -56
  64. data/lib/cyberarm_engine/ui/event.rb +47 -47
  65. data/lib/cyberarm_engine/ui/gui_state.rb +226 -135
  66. data/lib/cyberarm_engine/ui/style.rb +38 -37
  67. data/lib/cyberarm_engine/ui/theme.rb +182 -120
  68. data/lib/cyberarm_engine/vector.rb +293 -203
  69. data/lib/cyberarm_engine/version.rb +4 -4
  70. data/lib/cyberarm_engine/{engine.rb → window.rb} +114 -101
  71. metadata +88 -18
  72. data/lib/cyberarm_engine/gosu_ext/circle.rb +0 -9
  73. data/lib/cyberarm_engine/shader.rb +0 -262
@@ -1,135 +1,226 @@
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
- $__current_container__ = @root_container
16
-
17
- @active_width = window.width
18
- @active_height = window.height
19
-
20
- @focus = nil
21
- @mouse_over = nil
22
- @mouse_down_on = {}
23
- @mouse_down_position = {}
24
- @pending_recalculate_request = false
25
- end
26
-
27
- # throws :blur event to focused element and sets GuiState focused element
28
- # Does NOT throw :focus event at element or set element as focused
29
- def focus=(element)
30
- @focus.publish(:blur) if @focus and element && @focus != element
31
- @focus = element
32
- end
33
-
34
- def focused
35
- @focus
36
- end
37
-
38
- def update
39
- if @pending_recalculate_request
40
- @root_container.recalculate
41
- @pending_recalculate_request = false
42
- end
43
-
44
- super
45
-
46
- new_mouse_over = @root_container.hit_element?(window.mouse_x, window.mouse_y)
47
- if new_mouse_over
48
- new_mouse_over.publish(:enter) if new_mouse_over != @mouse_over
49
- new_mouse_over.publish(:hover)
50
- # 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
51
- end
52
- @mouse_over.publish(:leave) if @mouse_over && new_mouse_over != @mouse_over
53
- @mouse_over = new_mouse_over
54
-
55
- redirect_holding_mouse_button(:left) if @mouse_over && Gosu.button_down?(Gosu::MsLeft)
56
- redirect_holding_mouse_button(:middle) if @mouse_over && Gosu.button_down?(Gosu::MsMiddle)
57
- redirect_holding_mouse_button(:right) if @mouse_over && Gosu.button_down?(Gosu::MsRight)
58
-
59
- request_recalculate if @active_width != window.width || @active_height != window.height
60
-
61
- @active_width = window.width
62
- @active_height = window.height
63
- end
64
-
65
- def button_down(id)
66
- super
67
-
68
- case id
69
- when Gosu::MsLeft
70
- redirect_mouse_button(:left)
71
- when Gosu::MsMiddle
72
- redirect_mouse_button(:middle)
73
- when Gosu::MsRight
74
- redirect_mouse_button(:right)
75
- end
76
- end
77
-
78
- def button_up(id)
79
- super
80
-
81
- case id
82
- when Gosu::MsLeft
83
- redirect_released_mouse_button(:left)
84
- when Gosu::MsMiddle
85
- redirect_released_mouse_button(:middle)
86
- when Gosu::MsRight
87
- redirect_released_mouse_button(:right)
88
- when Gosu::MsWheelUp
89
- redirect_mouse_wheel(:up)
90
- when Gosu::MsWheelDown
91
- redirect_mouse_wheel(:down)
92
- end
93
- end
94
-
95
- def redirect_mouse_button(button)
96
- if @focus && @mouse_over != @focus
97
- @focus.publish(:blur)
98
- @focus = nil
99
- end
100
-
101
- if @mouse_over
102
- @mouse_down_position[button] = Vector.new(window.mouse_x, window.mouse_y)
103
- @mouse_down_on[button] = @mouse_over
104
-
105
- @mouse_over.publish(:"#{button}_mouse_button", window.mouse_x, window.mouse_y)
106
- else
107
- @mouse_down_position[button] = nil
108
- @mouse_down_on[button] = nil
109
- end
110
- end
111
-
112
- def redirect_released_mouse_button(button)
113
- if @mouse_over
114
- @mouse_over.publish(:"released_#{button}_mouse_button", window.mouse_x, window.mouse_y)
115
- @mouse_over.publish(:"clicked_#{button}_mouse_button", window.mouse_x, window.mouse_y) if @mouse_over == @mouse_down_on[button]
116
- end
117
-
118
- @mouse_down_position[button] = nil
119
- @mouse_down_on[button] = nil
120
- end
121
-
122
- def redirect_holding_mouse_button(button)
123
- @mouse_over.publish(:"holding_#{button}_mouse_button", window.mouse_x, window.mouse_y) if @mouse_over
124
- end
125
-
126
- def redirect_mouse_wheel(button)
127
- @mouse_over.publish(:"mouse_wheel_#{button}", window.mouse_x, window.mouse_y) if @mouse_over
128
- end
129
-
130
- # Schedule a full GUI recalculation on next update
131
- def request_recalculate
132
- @pending_recalculate_request = true
133
- end
134
- end
135
- 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
+ $__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
+
29
+ @tip = Element::ToolTip.new("", parent: @root_container, z: Float::INFINITY)
30
+ @menu = nil
31
+ @min_drag_distance = 0
32
+ @mouse_pos = Vector.new
33
+ end
34
+
35
+ # throws :blur event to focused element and sets GuiState focused element
36
+ # Does NOT throw :focus event at element or set element as focused
37
+ def focus=(element)
38
+ @focus.publish(:blur) if @focus && element && @focus != element
39
+ @focus = element
40
+ end
41
+
42
+ def focused
43
+ @focus
44
+ end
45
+
46
+ def draw
47
+ super
48
+
49
+ if @menu
50
+ Gosu.flush
51
+ @menu.draw
52
+ end
53
+
54
+ if @tip.value.length.positive?
55
+ Gosu.flush
56
+ @tip.draw
57
+ end
58
+ end
59
+
60
+ def update
61
+ if @pending_recalculate_request
62
+ @root_container.recalculate
63
+ @root_container.recalculate
64
+ @root_container.recalculate
65
+
66
+ @pending_recalculate_request = false
67
+ end
68
+
69
+ @menu&.update
70
+ super
71
+
72
+ new_mouse_over = @menu.hit_element?(window.mouse_x, window.mouse_y) if @menu
73
+ new_mouse_over ||= @root_container.hit_element?(window.mouse_x, window.mouse_y)
74
+
75
+ if new_mouse_over
76
+ new_mouse_over.publish(:enter) if new_mouse_over != @mouse_over
77
+ new_mouse_over.publish(:hover)
78
+ # 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
79
+ end
80
+ @mouse_over.publish(:leave) if @mouse_over && new_mouse_over != @mouse_over
81
+ @mouse_over = new_mouse_over
82
+
83
+ redirect_holding_mouse_button(:left) if @mouse_over && Gosu.button_down?(Gosu::MsLeft)
84
+ redirect_holding_mouse_button(:middle) if @mouse_over && Gosu.button_down?(Gosu::MsMiddle)
85
+ redirect_holding_mouse_button(:right) if @mouse_over && Gosu.button_down?(Gosu::MsRight)
86
+
87
+ if Vector.new(window.mouse_x, window.mouse_y) == @last_mouse_pos
88
+ if @mouse_over && (Gosu.milliseconds - @mouse_moved_at) > tool_tip_delay
89
+ @tip.value = @mouse_over.tip if @mouse_over
90
+ @tip.x = window.mouse_x - @tip.width / 2
91
+ @tip.x = 0 if @tip.x < 0
92
+ @tip.x = window.width - @tip.width if @tip.x + @tip.width > window.width
93
+ @tip.y = window.mouse_y - @tip.height
94
+ @tip.y = 0 if @tip.y < 0
95
+ @tip.y = window.height - @tip.height if @tip.y + @tip.height > window.height
96
+ @tip.update
97
+ @tip.recalculate
98
+ else
99
+ @tip.value = ""
100
+ end
101
+ else
102
+ @mouse_moved_at = Gosu.milliseconds
103
+ end
104
+
105
+ @last_mouse_pos = Vector.new(window.mouse_x, window.mouse_y)
106
+ @mouse_pos = @last_mouse_pos.clone
107
+
108
+ if @active_width != window.width || @active_height != window.height
109
+ request_recalculate
110
+ @root_container.publish(:window_size_changed)
111
+ end
112
+
113
+ @active_width = window.width
114
+ @active_height = window.height
115
+ end
116
+
117
+ def tool_tip_delay
118
+ 250 # ms
119
+ end
120
+
121
+ def button_down(id)
122
+ super
123
+
124
+ case id
125
+ when Gosu::MsLeft
126
+ redirect_mouse_button(:left)
127
+ when Gosu::MsMiddle
128
+ redirect_mouse_button(:middle)
129
+ when Gosu::MsRight
130
+ redirect_mouse_button(:right)
131
+ when Gosu::KbF5
132
+ request_recalculate
133
+ end
134
+
135
+ @focus.button_down(id) if @focus.respond_to?(:button_down)
136
+ end
137
+
138
+ def button_up(id)
139
+ super
140
+
141
+ case id
142
+ when Gosu::MsLeft
143
+ redirect_released_mouse_button(:left)
144
+ when Gosu::MsMiddle
145
+ redirect_released_mouse_button(:middle)
146
+ when Gosu::MsRight
147
+ redirect_released_mouse_button(:right)
148
+ when Gosu::MsWheelUp
149
+ redirect_mouse_wheel(:up)
150
+ when Gosu::MsWheelDown
151
+ redirect_mouse_wheel(:down)
152
+ end
153
+
154
+ @focus.button_up(id) if @focus.respond_to?(:button_up)
155
+ end
156
+
157
+ def redirect_mouse_button(button)
158
+ hide_menu unless @menu && (@menu == @mouse_over) || (@mouse_over&.parent == @menu)
159
+
160
+ if @focus && @mouse_over != @focus
161
+ @focus.publish(:blur)
162
+ @focus = nil
163
+ end
164
+
165
+ if @mouse_over
166
+ @mouse_down_position[button] = Vector.new(window.mouse_x, window.mouse_y)
167
+ @mouse_down_on[button] = @mouse_over
168
+
169
+ @mouse_over.publish(:"#{button}_mouse_button", window.mouse_x, window.mouse_y)
170
+ else
171
+ @mouse_down_position[button] = nil
172
+ @mouse_down_on[button] = nil
173
+ end
174
+ end
175
+
176
+ def redirect_released_mouse_button(button)
177
+ hide_menu if @menu && (@menu == @mouse_over) || (@mouse_over&.parent == @menu)
178
+
179
+ if @mouse_over
180
+ @mouse_over.publish(:"released_#{button}_mouse_button", window.mouse_x, window.mouse_y)
181
+ if @mouse_over == @mouse_down_on[button]
182
+ @mouse_over.publish(:"clicked_#{button}_mouse_button", window.mouse_x,
183
+ window.mouse_y)
184
+ end
185
+ end
186
+
187
+ if @dragging_element
188
+ @dragging_element.publish(:end_drag, window.mouse_x, window.mouse_y, button)
189
+ @dragging_element = nil
190
+ end
191
+
192
+ @mouse_down_position[button] = nil
193
+ @mouse_down_on[button] = nil
194
+ end
195
+
196
+ def redirect_holding_mouse_button(button)
197
+ if !@dragging_element && @mouse_down_on[button] && @mouse_down_on[button].draggable?(button) && @mouse_pos.distance(@mouse_down_position[button]) > @min_drag_distance
198
+ @dragging_element = @mouse_down_on[button]
199
+ @dragging_element.publish(:begin_drag, window.mouse_x, window.mouse_y, button)
200
+ end
201
+
202
+ if @dragging_element
203
+ @dragging_element.publish(:drag_update, window.mouse_x, window.mouse_y, button) if @dragging_element
204
+ elsif @mouse_over
205
+ @mouse_over.publish(:"holding_#{button}_mouse_button", window.mouse_x, window.mouse_y)
206
+ end
207
+ end
208
+
209
+ def redirect_mouse_wheel(button)
210
+ @mouse_over.publish(:"mouse_wheel_#{button}", window.mouse_x, window.mouse_y) if @mouse_over
211
+ end
212
+
213
+ # Schedule a full GUI recalculation on next update
214
+ def request_recalculate
215
+ @pending_recalculate_request = true
216
+ end
217
+
218
+ def show_menu(list_box)
219
+ @menu = list_box
220
+ end
221
+
222
+ def hide_menu
223
+ @menu = nil
224
+ end
225
+ end
226
+ end
@@ -1,37 +1,38 @@
1
- module Gosu
2
- class Color
3
- def _dump(level)
4
- [
5
- "%02X" % self.alpha,
6
- "%02X" % self.red,
7
- "%02X" % self.green,
8
- "%02X" % self.blue
9
- ].join
10
- end
11
-
12
- def self._load(hex)
13
- argb(hex.to_i(16))
14
- end
15
- end
16
- end
17
-
18
- module CyberarmEngine
19
- class Style
20
- def initialize(hash = {})
21
- @hash = Marshal.load(Marshal.dump(hash))
22
- end
23
-
24
- def method_missing(method, *args, &block)
25
- if method.to_s.end_with?("=")
26
- raise "Did not expect more than 1 argument" if args.size > 1
27
- return @hash[method.to_s.sub("=", "").to_sym] = args.first
28
-
29
- elsif args.size == 0
30
- return @hash[method]
31
-
32
- else
33
- raise ArgumentError, "Did not expect arguments"
34
- end
35
- end
36
- end
37
- end
1
+ module Gosu
2
+ class Color
3
+ def _dump(_level)
4
+ [
5
+ "%02X" % alpha,
6
+ "%02X" % red,
7
+ "%02X" % green,
8
+ "%02X" % blue
9
+ ].join
10
+ end
11
+
12
+ def self._load(hex)
13
+ argb(hex.to_i(16))
14
+ end
15
+ end
16
+ end
17
+
18
+ module CyberarmEngine
19
+ class Style
20
+ def initialize(hash = {})
21
+ @hash = Marshal.load(Marshal.dump(hash))
22
+ end
23
+
24
+ def method_missing(method, *args)
25
+ if method.to_s.end_with?("=")
26
+ raise "Did not expect more than 1 argument" if args.size > 1
27
+
28
+ @hash[method.to_s.sub("=", "").to_sym] = args.first
29
+
30
+ elsif args.size == 0
31
+ @hash[method]
32
+
33
+ else
34
+ raise ArgumentError, "Did not expect arguments"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1,120 +1,182 @@
1
- module CyberarmEngine
2
- module Theme
3
- def default(*args)
4
- value = @options
5
- args.each do |arg|
6
- value = value.dig(arg)
7
- end
8
-
9
- value
10
- end
11
-
12
- def theme_defaults(options)
13
- raise "Error" unless self.class.ancestors.include?(CyberarmEngine::Element)
14
- _theme = THEME
15
- _theme = _theme.merge(options[:theme]) if options[:theme]
16
- _theme.delete(:theme) if options[:theme]
17
-
18
- hash = {}
19
- class_names = self.class.ancestors
20
- class_names = class_names[0..class_names.index(CyberarmEngine::Element)].map! {|c| c.to_s.split("::").last.to_sym}.reverse!
21
-
22
- class_names.each do |klass|
23
- next unless data = _theme.dig(klass)
24
- data.each do |key, value|
25
- hash.merge!(data)
26
- end
27
- end
28
-
29
- deep_merge(hash, options)
30
- end
31
-
32
- # Derived from Rails Hash#deep_merge!
33
- # Enables passing partial themes through Element options without issue
34
- def deep_merge(original, intergrate, &block)
35
- hash = original.merge(intergrate) do |key, this_val, other_val|
36
- if this_val.is_a?(Hash) && other_val.is_a?(Hash)
37
- deep_merge(this_val, other_val, &block)
38
- elsif block_given?
39
- block.call(key, this_val, other_val)
40
- else
41
- other_val
42
- end
43
- end
44
-
45
- return hash
46
- end
47
-
48
- THEME = {
49
- Element: {
50
- x: 0,
51
- y: 0,
52
- z: 30,
53
-
54
- width: nil,
55
- height: nil,
56
- color: Gosu::Color::WHITE,
57
- background: Gosu::Color::NONE,
58
- margin: 0,
59
- padding: 0,
60
- border_thickness: 0,
61
- border_color: Gosu::Color::NONE,
62
- border_radius: 0,
63
- },
64
-
65
- Button: { # < Label
66
- margin: 1,
67
- padding: 4,
68
- border_thickness: 1,
69
- border_color: ["ffd59674".hex, "ffff8746".hex],
70
- border_radius: 0,
71
- background: ["ffc75e61".to_i(16), "ffe26623".to_i(16)],
72
-
73
- hover: {
74
- color: Gosu::Color.rgb(200,200,200),
75
- background: ["ffB23E41".to_i(16), "ffFF7C00".to_i(16)],
76
- },
77
-
78
- active: {
79
- color: Gosu::Color::BLACK,
80
- background: ["ffB23E41".to_i(16)]
81
- }
82
- },
83
-
84
- EditLine: { # < Button
85
- type: :text,
86
- width: 200,
87
- password_character: "•",
88
- caret_width: 2,
89
- caret_color: Gosu::Color::WHITE,
90
- caret_interval: 500,
91
- selection_color: Gosu::Color::GREEN,
92
- },
93
-
94
- Image: { # < Element
95
- retro: false
96
- },
97
-
98
- Label: { # < Element
99
- text_size: 28,
100
- text_shadow: false,
101
- font: "Arial",
102
- margin: 0,
103
- padding: 2
104
- },
105
-
106
- ToggleButton: { # < Button
107
- checkmark: "√"
108
- },
109
-
110
- Progress: { # < Element
111
- width: 250,
112
- height: 36,
113
- background: 0xff111111,
114
- fraction_background: [0xffc75e61, 0xffe26623],
115
- border_thickness: 1,
116
- border_color: [0xffd59674, 0xffff8746]
117
- }
118
- }.freeze
119
- end
120
- end
1
+ module CyberarmEngine
2
+ module Theme
3
+ def default(*args)
4
+ value = @options
5
+ args.each do |arg|
6
+ value = value.dig(arg)
7
+ end
8
+
9
+ value
10
+ end
11
+
12
+ def theme_defaults(options)
13
+ raise "Error" unless self.class.ancestors.include?(CyberarmEngine::Element)
14
+
15
+ _theme = THEME
16
+ _theme = deep_merge(_theme, options[:theme]) if options[:theme]
17
+ _theme.delete(:theme) if options[:theme]
18
+
19
+ hash = {}
20
+ class_names = self.class.ancestors
21
+ class_names = class_names[0..class_names.index(CyberarmEngine::Element)].map! do |c|
22
+ c.to_s.split("::").last.to_sym
23
+ end.reverse!
24
+
25
+ class_names.each do |klass|
26
+ next unless data = _theme.dig(klass)
27
+
28
+ data.each do |_key, _value|
29
+ hash.merge!(data)
30
+ end
31
+ end
32
+
33
+ deep_merge(hash, options)
34
+ end
35
+
36
+ # Derived from Rails Hash#deep_merge!
37
+ # Enables passing partial themes through Element options without issue
38
+ def deep_merge(original, intergrate, &block)
39
+ original.merge(intergrate) do |key, this_val, other_val|
40
+ if this_val.is_a?(Hash) && other_val.is_a?(Hash)
41
+ deep_merge(this_val, other_val, &block)
42
+ elsif block_given?
43
+ block.call(key, this_val, other_val)
44
+ else
45
+ other_val
46
+ end
47
+ end
48
+ end
49
+
50
+ THEME = {
51
+ Element: {
52
+ x: 0,
53
+ y: 0,
54
+ z: 30,
55
+
56
+ width: nil,
57
+ height: nil,
58
+ color: Gosu::Color::WHITE,
59
+ background: Gosu::Color::NONE,
60
+ margin: 0,
61
+ padding: 0,
62
+ border_thickness: 0,
63
+ border_color: Gosu::Color::NONE,
64
+ border_radius: 0
65
+ },
66
+
67
+ Button: { # < Label
68
+ margin: 1,
69
+ padding: 4,
70
+ border_thickness: 1,
71
+ border_color: ["ffd59674".hex, "ffff8746".hex],
72
+ border_radius: 0,
73
+ background: ["ffc75e61".to_i(16), "ffe26623".to_i(16)],
74
+ text_align: :center,
75
+ text_wrap: :none,
76
+
77
+ hover: {
78
+ color: Gosu::Color.rgb(200, 200, 200),
79
+ background: ["ffB23E41".to_i(16), "ffFF7C00".to_i(16)]
80
+ },
81
+
82
+ active: {
83
+ color: Gosu::Color::BLACK,
84
+ background: ["ffB23E41".to_i(16)]
85
+ },
86
+
87
+ disabled: {
88
+ color: Gosu::Color::GRAY,
89
+ background: 0xff303030
90
+ }
91
+ },
92
+
93
+ EditLine: { # < Button
94
+ type: :text,
95
+ width: 200,
96
+ password_character: "•",
97
+ caret_width: 2,
98
+ caret_color: Gosu::Color::WHITE,
99
+ caret_interval: 500,
100
+ selection_color: Gosu::Color.rgba(255, 128, 50, 200),
101
+ text_align: :left
102
+ },
103
+
104
+ Image: { # < Element
105
+ color: Gosu::Color::WHITE,
106
+ tileable: false,
107
+ retro: false
108
+ },
109
+
110
+ TextBlock: { # < Element
111
+ text_size: 28,
112
+ text_wrap: :word_wrap, # :word_wrap, :break_word, :none
113
+ text_shadow: false,
114
+ text_align: :left,
115
+ font: "Arial",
116
+ margin: 0,
117
+ padding: 2
118
+ },
119
+
120
+ Banner: { # < TextBlock
121
+ text_size: 48
122
+ },
123
+
124
+ Title: { # < TextBlock
125
+ text_size: 34
126
+ },
127
+
128
+ Subtitle: { # < TextBlock
129
+ text_size: 26
130
+ },
131
+
132
+ Tagline: { # < TextBlock
133
+ text_size: 24
134
+ },
135
+
136
+ Caption: { # < TextBlock
137
+ text_size: 22
138
+ },
139
+
140
+ Para: { # < TextBlock
141
+ text_size: 18
142
+ },
143
+
144
+ Inscription: { # < TextBlock
145
+ text_size: 16
146
+ },
147
+
148
+ ToolTip: { # < TextBlock
149
+ color: Gosu::Color::WHITE,
150
+ padding_top: 4,
151
+ padding_bottom: 4,
152
+ padding_left: 8,
153
+ padding_right: 8,
154
+ border_thickness: 1,
155
+ border_color: 0xffaaaaaa,
156
+ background: 0xff404040
157
+ },
158
+
159
+ ToggleButton: { # < Button
160
+ checkmark: "√"
161
+ },
162
+
163
+ Progress: { # < Element
164
+ width: 250,
165
+ height: 36,
166
+ background: 0xff111111,
167
+ fraction_background: [0xffc75e61, 0xffe26623],
168
+ border_thickness: 1,
169
+ border_color: [0xffd59674, 0xffff8746]
170
+ },
171
+
172
+ Slider: { # < Element
173
+ width: 250,
174
+ height: 36,
175
+ background: 0xff111111,
176
+ fraction_background: [0xffc75e61, 0xffe26623],
177
+ border_thickness: 1,
178
+ border_color: [0xffd59674, 0xffff8746]
179
+ }
180
+ }.freeze
181
+ end
182
+ end