cyberarm_engine 0.13.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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