gemba 0.1.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.
- checksums.yaml +7 -0
- data/THIRD_PARTY_NOTICES +113 -0
- data/assets/JetBrainsMonoNL-Regular.ttf +0 -0
- data/assets/ark-pixel-12px-monospaced-ja.ttf +0 -0
- data/bin/gemba +14 -0
- data/ext/gemba/extconf.rb +185 -0
- data/ext/gemba/gemba_ext.c +1051 -0
- data/ext/gemba/gemba_ext.h +15 -0
- data/gemba.gemspec +38 -0
- data/lib/gemba/child_window.rb +62 -0
- data/lib/gemba/cli.rb +384 -0
- data/lib/gemba/config.rb +621 -0
- data/lib/gemba/core.rb +121 -0
- data/lib/gemba/headless.rb +12 -0
- data/lib/gemba/headless_player.rb +206 -0
- data/lib/gemba/hotkey_map.rb +202 -0
- data/lib/gemba/input_mappings.rb +214 -0
- data/lib/gemba/locale.rb +92 -0
- data/lib/gemba/locales/en.yml +157 -0
- data/lib/gemba/locales/ja.yml +157 -0
- data/lib/gemba/method_coverage_service.rb +265 -0
- data/lib/gemba/overlay_renderer.rb +109 -0
- data/lib/gemba/player.rb +1515 -0
- data/lib/gemba/recorder.rb +156 -0
- data/lib/gemba/recorder_decoder.rb +325 -0
- data/lib/gemba/rom_info_window.rb +346 -0
- data/lib/gemba/rom_loader.rb +100 -0
- data/lib/gemba/runtime.rb +39 -0
- data/lib/gemba/save_state_manager.rb +155 -0
- data/lib/gemba/save_state_picker.rb +199 -0
- data/lib/gemba/settings_window.rb +1173 -0
- data/lib/gemba/tip_service.rb +133 -0
- data/lib/gemba/toast_overlay.rb +128 -0
- data/lib/gemba/version.rb +5 -0
- data/lib/gemba.rb +17 -0
- data/test/fixtures/test.gba +0 -0
- data/test/fixtures/test.sav +0 -0
- data/test/shared/screenshot_helper.rb +113 -0
- data/test/shared/simplecov_config.rb +59 -0
- data/test/shared/teek_test_worker.rb +388 -0
- data/test/shared/tk_test_helper.rb +354 -0
- data/test/support/input_mocks.rb +61 -0
- data/test/support/player_helpers.rb +77 -0
- data/test/test_cli.rb +281 -0
- data/test/test_config.rb +897 -0
- data/test/test_core.rb +401 -0
- data/test/test_gamepad_map.rb +116 -0
- data/test/test_headless_player.rb +205 -0
- data/test/test_helper.rb +19 -0
- data/test/test_hotkey_map.rb +396 -0
- data/test/test_keyboard_map.rb +108 -0
- data/test/test_locale.rb +159 -0
- data/test/test_mgba.rb +26 -0
- data/test/test_overlay_renderer.rb +199 -0
- data/test/test_player.rb +903 -0
- data/test/test_recorder.rb +180 -0
- data/test/test_rom_loader.rb +149 -0
- data/test/test_save_state_manager.rb +289 -0
- data/test/test_settings_hotkeys.rb +434 -0
- data/test/test_settings_window.rb +1039 -0
- data/test/test_tip_service.rb +138 -0
- data/test/test_toast_overlay.rb +216 -0
- data/test/test_virtual_keyboard.rb +39 -0
- data/test/test_xor_delta.rb +61 -0
- metadata +234 -0
|
@@ -0,0 +1,1039 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "minitest/autorun"
|
|
4
|
+
require_relative "shared/tk_test_helper"
|
|
5
|
+
|
|
6
|
+
class TestMGBASettingsWindow < Minitest::Test
|
|
7
|
+
include TeekTestHelper
|
|
8
|
+
|
|
9
|
+
# -- Video scale --------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
def test_scale_combobox_defaults_to_3x
|
|
12
|
+
assert_tk_app("scale combobox defaults to 3x") do
|
|
13
|
+
require "gemba/settings_window"
|
|
14
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
15
|
+
sw.show
|
|
16
|
+
app.update
|
|
17
|
+
|
|
18
|
+
assert_equal '3x', app.get_variable(Gemba::SettingsWindow::VAR_SCALE)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def test_selecting_2x_scale_fires_callback
|
|
23
|
+
assert_tk_app("selecting 2x scale fires on_scale_change") do
|
|
24
|
+
require "gemba/settings_window"
|
|
25
|
+
received = nil
|
|
26
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
27
|
+
on_scale_change: proc { |s| received = s }
|
|
28
|
+
})
|
|
29
|
+
sw.show
|
|
30
|
+
app.update
|
|
31
|
+
|
|
32
|
+
# Simulate user selecting "2x" from the combobox
|
|
33
|
+
app.set_variable(Gemba::SettingsWindow::VAR_SCALE, '2x')
|
|
34
|
+
app.command(:event, 'generate', Gemba::SettingsWindow::SCALE_COMBO, '<<ComboboxSelected>>')
|
|
35
|
+
app.update
|
|
36
|
+
|
|
37
|
+
assert_equal 2, received
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def test_selecting_4x_scale_fires_callback
|
|
42
|
+
assert_tk_app("selecting 4x scale fires on_scale_change") do
|
|
43
|
+
require "gemba/settings_window"
|
|
44
|
+
received = nil
|
|
45
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
46
|
+
on_scale_change: proc { |s| received = s }
|
|
47
|
+
})
|
|
48
|
+
sw.show
|
|
49
|
+
app.update
|
|
50
|
+
|
|
51
|
+
app.set_variable(Gemba::SettingsWindow::VAR_SCALE, '4x')
|
|
52
|
+
app.command(:event, 'generate', Gemba::SettingsWindow::SCALE_COMBO, '<<ComboboxSelected>>')
|
|
53
|
+
app.update
|
|
54
|
+
|
|
55
|
+
assert_equal 4, received
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# -- Volume slider ------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
def test_volume_defaults_to_100
|
|
62
|
+
assert_tk_app("volume defaults to 100") do
|
|
63
|
+
require "gemba/settings_window"
|
|
64
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
65
|
+
sw.show
|
|
66
|
+
app.update
|
|
67
|
+
|
|
68
|
+
assert_equal '100', app.get_variable(Gemba::SettingsWindow::VAR_VOLUME)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def test_dragging_volume_to_50_fires_callback
|
|
73
|
+
assert_tk_app("dragging volume to 50 fires on_volume_change") do
|
|
74
|
+
require "gemba/settings_window"
|
|
75
|
+
received = nil
|
|
76
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
77
|
+
on_volume_change: proc { |v| received = v }
|
|
78
|
+
})
|
|
79
|
+
sw.show
|
|
80
|
+
app.update
|
|
81
|
+
|
|
82
|
+
# Simulate user dragging volume slider to 50
|
|
83
|
+
app.command(Gemba::SettingsWindow::VOLUME_SCALE, 'set', 50)
|
|
84
|
+
app.update
|
|
85
|
+
|
|
86
|
+
assert_in_delta 0.5, received, 0.01
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def test_volume_at_zero
|
|
91
|
+
assert_tk_app("volume at zero") do
|
|
92
|
+
require "gemba/settings_window"
|
|
93
|
+
received = nil
|
|
94
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
95
|
+
on_volume_change: proc { |v| received = v }
|
|
96
|
+
})
|
|
97
|
+
sw.show
|
|
98
|
+
app.update
|
|
99
|
+
|
|
100
|
+
app.command(Gemba::SettingsWindow::VOLUME_SCALE, 'set', 0)
|
|
101
|
+
app.update
|
|
102
|
+
|
|
103
|
+
assert_in_delta 0.0, received, 0.01
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# -- Mute checkbox ------------------------------------------------------
|
|
108
|
+
|
|
109
|
+
def test_mute_defaults_to_off
|
|
110
|
+
assert_tk_app("mute defaults to off") do
|
|
111
|
+
require "gemba/settings_window"
|
|
112
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
113
|
+
sw.show
|
|
114
|
+
app.update
|
|
115
|
+
|
|
116
|
+
assert_equal '0', app.get_variable(Gemba::SettingsWindow::VAR_MUTE)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def test_clicking_mute_fires_callback
|
|
121
|
+
assert_tk_app("clicking mute fires on_mute_change") do
|
|
122
|
+
require "gemba/settings_window"
|
|
123
|
+
received = nil
|
|
124
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
125
|
+
on_mute_change: proc { |m| received = m }
|
|
126
|
+
})
|
|
127
|
+
sw.show
|
|
128
|
+
app.update
|
|
129
|
+
|
|
130
|
+
# Simulate user clicking the mute checkbox
|
|
131
|
+
app.command(Gemba::SettingsWindow::MUTE_CHECK, 'invoke')
|
|
132
|
+
app.update
|
|
133
|
+
|
|
134
|
+
assert_equal true, received
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def test_clicking_mute_twice_unmutes
|
|
139
|
+
assert_tk_app("clicking mute twice unmutes") do
|
|
140
|
+
require "gemba/settings_window"
|
|
141
|
+
received = nil
|
|
142
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
143
|
+
on_mute_change: proc { |m| received = m }
|
|
144
|
+
})
|
|
145
|
+
sw.show
|
|
146
|
+
app.update
|
|
147
|
+
|
|
148
|
+
app.command(Gemba::SettingsWindow::MUTE_CHECK, 'invoke')
|
|
149
|
+
app.update
|
|
150
|
+
assert_equal true, received
|
|
151
|
+
|
|
152
|
+
app.command(Gemba::SettingsWindow::MUTE_CHECK, 'invoke')
|
|
153
|
+
app.update
|
|
154
|
+
assert_equal false, received
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# -- Window lifecycle ---------------------------------------------------
|
|
159
|
+
|
|
160
|
+
def test_settings_starts_hidden
|
|
161
|
+
assert_tk_app("settings starts hidden") do
|
|
162
|
+
require "gemba/settings_window"
|
|
163
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
164
|
+
app.update
|
|
165
|
+
|
|
166
|
+
assert_equal 'withdrawn', app.command(:wm, 'state', Gemba::SettingsWindow::TOP)
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def test_show_and_hide
|
|
171
|
+
assert_tk_app("show makes window visible, hide withdraws it") do
|
|
172
|
+
require "gemba/settings_window"
|
|
173
|
+
app.show
|
|
174
|
+
app.update
|
|
175
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
176
|
+
|
|
177
|
+
sw.show
|
|
178
|
+
app.command(:focus, '-force', Gemba::SettingsWindow::TOP)
|
|
179
|
+
app.update
|
|
180
|
+
assert_equal 'normal', app.command(:wm, 'state', Gemba::SettingsWindow::TOP)
|
|
181
|
+
|
|
182
|
+
sw.hide
|
|
183
|
+
app.update
|
|
184
|
+
assert_equal 'withdrawn', app.command(:wm, 'state', Gemba::SettingsWindow::TOP)
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# -- Gamepad tab ---------------------------------------------------------
|
|
189
|
+
|
|
190
|
+
def test_gamepad_tab_exists
|
|
191
|
+
assert_tk_app("gamepad tab exists in notebook") do
|
|
192
|
+
require "gemba/settings_window"
|
|
193
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
194
|
+
sw.show
|
|
195
|
+
app.update
|
|
196
|
+
|
|
197
|
+
tabs = app.command(Gemba::SettingsWindow::NB, 'tabs')
|
|
198
|
+
assert_includes tabs, Gemba::SettingsWindow::GAMEPAD_TAB
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def test_deadzone_defaults_to_25
|
|
203
|
+
assert_tk_app("dead zone defaults to 25") do
|
|
204
|
+
require "gemba/settings_window"
|
|
205
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
206
|
+
sw.show
|
|
207
|
+
app.update
|
|
208
|
+
|
|
209
|
+
assert_equal '25', app.get_variable(Gemba::SettingsWindow::VAR_DEADZONE)
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def test_deadzone_change_fires_callback
|
|
214
|
+
assert_tk_app("dead zone change fires on_deadzone_change") do
|
|
215
|
+
require "gemba/settings_window"
|
|
216
|
+
received = nil
|
|
217
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
218
|
+
on_deadzone_change: proc { |t| received = t }
|
|
219
|
+
})
|
|
220
|
+
sw.show
|
|
221
|
+
app.update
|
|
222
|
+
|
|
223
|
+
# Switch to gamepad mode (dead zone is disabled in keyboard mode)
|
|
224
|
+
sw.update_gamepad_list(['Keyboard Only', 'Test Gamepad'])
|
|
225
|
+
app.set_variable(Gemba::SettingsWindow::VAR_GAMEPAD, 'Test Gamepad')
|
|
226
|
+
app.command(:event, 'generate', Gemba::SettingsWindow::GAMEPAD_COMBO, '<<ComboboxSelected>>')
|
|
227
|
+
app.update
|
|
228
|
+
|
|
229
|
+
app.command(Gemba::SettingsWindow::DEADZONE_SCALE, 'set', 15)
|
|
230
|
+
app.update
|
|
231
|
+
|
|
232
|
+
# 15% of 32767 ≈ 4915
|
|
233
|
+
assert_equal 4915, received
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def test_clicking_gba_button_enters_listen_mode
|
|
238
|
+
assert_tk_app("clicking GBA button enters listen mode") do
|
|
239
|
+
require "gemba/settings_window"
|
|
240
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
241
|
+
sw.show
|
|
242
|
+
app.update
|
|
243
|
+
|
|
244
|
+
# Click the A button
|
|
245
|
+
app.command(Gemba::SettingsWindow::GP_BTN_A, 'invoke')
|
|
246
|
+
app.update
|
|
247
|
+
|
|
248
|
+
assert_equal :a, sw.listening_for
|
|
249
|
+
text = app.command(Gemba::SettingsWindow::GP_BTN_A, 'cget', '-text')
|
|
250
|
+
assert_equal "Press\u2026", text
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def test_capture_mapping_updates_button_label
|
|
255
|
+
assert_tk_app("capture_mapping updates button label") do
|
|
256
|
+
require "gemba/settings_window"
|
|
257
|
+
received_gba = nil
|
|
258
|
+
received_key = nil
|
|
259
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
260
|
+
on_keyboard_map_change: proc { |g, b| received_gba = g; received_key = b }
|
|
261
|
+
})
|
|
262
|
+
sw.show
|
|
263
|
+
app.update
|
|
264
|
+
|
|
265
|
+
# Default mode is keyboard — enter listen mode for A
|
|
266
|
+
app.command(Gemba::SettingsWindow::GP_BTN_A, 'invoke')
|
|
267
|
+
app.update
|
|
268
|
+
|
|
269
|
+
# Simulate keyboard key capture
|
|
270
|
+
sw.capture_mapping('q')
|
|
271
|
+
app.update
|
|
272
|
+
|
|
273
|
+
assert_nil sw.listening_for
|
|
274
|
+
assert_equal :a, received_gba
|
|
275
|
+
assert_equal 'q', received_key
|
|
276
|
+
text = app.command(Gemba::SettingsWindow::GP_BTN_A, 'cget', '-text')
|
|
277
|
+
assert_equal 'q', text
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
def test_gamepad_selector_defaults_to_keyboard_only
|
|
282
|
+
assert_tk_app("gamepad selector defaults to Keyboard Only") do
|
|
283
|
+
require "gemba/settings_window"
|
|
284
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
285
|
+
sw.show
|
|
286
|
+
app.update
|
|
287
|
+
|
|
288
|
+
assert_equal 'Keyboard Only', app.get_variable(Gemba::SettingsWindow::VAR_GAMEPAD)
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
# -- Undo button ----------------------------------------------------------
|
|
293
|
+
|
|
294
|
+
def test_undo_starts_disabled
|
|
295
|
+
assert_tk_app("undo button starts disabled") do
|
|
296
|
+
require "gemba/settings_window"
|
|
297
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
298
|
+
sw.show
|
|
299
|
+
app.update
|
|
300
|
+
|
|
301
|
+
state = app.command(Gemba::SettingsWindow::GP_UNDO_BTN, 'cget', '-state')
|
|
302
|
+
assert_equal 'disabled', state
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def test_undo_enabled_after_remap
|
|
307
|
+
assert_tk_app("undo enabled after capturing a mapping") do
|
|
308
|
+
require "gemba/settings_window"
|
|
309
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
310
|
+
sw.show
|
|
311
|
+
app.update
|
|
312
|
+
|
|
313
|
+
app.command(Gemba::SettingsWindow::GP_BTN_A, 'invoke')
|
|
314
|
+
app.update
|
|
315
|
+
sw.capture_mapping(:x)
|
|
316
|
+
app.update
|
|
317
|
+
|
|
318
|
+
state = app.command(Gemba::SettingsWindow::GP_UNDO_BTN, 'cget', '-state')
|
|
319
|
+
assert_equal 'normal', state
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
def test_undo_fires_callback_and_disables
|
|
324
|
+
assert_tk_app("undo fires on_undo_gamepad and disables itself") do
|
|
325
|
+
require "gemba/settings_window"
|
|
326
|
+
undo_called = false
|
|
327
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
328
|
+
on_undo_gamepad: proc { undo_called = true }
|
|
329
|
+
})
|
|
330
|
+
sw.show
|
|
331
|
+
app.update
|
|
332
|
+
|
|
333
|
+
# Remap to enable undo
|
|
334
|
+
app.command(Gemba::SettingsWindow::GP_BTN_A, 'invoke')
|
|
335
|
+
app.update
|
|
336
|
+
sw.capture_mapping(:x)
|
|
337
|
+
app.update
|
|
338
|
+
|
|
339
|
+
# Click undo
|
|
340
|
+
app.command(Gemba::SettingsWindow::GP_UNDO_BTN, 'invoke')
|
|
341
|
+
app.update
|
|
342
|
+
|
|
343
|
+
assert undo_called
|
|
344
|
+
state = app.command(Gemba::SettingsWindow::GP_UNDO_BTN, 'cget', '-state')
|
|
345
|
+
assert_equal 'disabled', state
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
def test_reset_disables_undo
|
|
350
|
+
assert_tk_app("reset to defaults disables undo button") do
|
|
351
|
+
require "gemba/settings_window"
|
|
352
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
353
|
+
sw.show
|
|
354
|
+
app.update
|
|
355
|
+
|
|
356
|
+
# Remap to enable undo
|
|
357
|
+
app.command(Gemba::SettingsWindow::GP_BTN_A, 'invoke')
|
|
358
|
+
app.update
|
|
359
|
+
sw.capture_mapping(:x)
|
|
360
|
+
app.update
|
|
361
|
+
|
|
362
|
+
state = app.command(Gemba::SettingsWindow::GP_UNDO_BTN, 'cget', '-state')
|
|
363
|
+
assert_equal 'normal', state
|
|
364
|
+
|
|
365
|
+
# refresh_gamepad simulates what reset/undo would do from the player side
|
|
366
|
+
sw.refresh_gamepad(Gemba::SettingsWindow::DEFAULT_GP_LABELS, 25)
|
|
367
|
+
app.update
|
|
368
|
+
|
|
369
|
+
# Verify labels restored
|
|
370
|
+
text = app.command(Gemba::SettingsWindow::GP_BTN_A, 'cget', '-text')
|
|
371
|
+
assert_equal 'a', text
|
|
372
|
+
end
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
# -- Aspect ratio checkbox ------------------------------------------------
|
|
376
|
+
|
|
377
|
+
def test_aspect_ratio_defaults_to_on
|
|
378
|
+
assert_tk_app("aspect ratio checkbox defaults to on") do
|
|
379
|
+
require "gemba/settings_window"
|
|
380
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
381
|
+
sw.show
|
|
382
|
+
app.update
|
|
383
|
+
|
|
384
|
+
assert_equal '1', app.get_variable(Gemba::SettingsWindow::VAR_ASPECT_RATIO)
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
def test_unchecking_aspect_ratio_fires_callback
|
|
389
|
+
assert_tk_app("unchecking aspect ratio fires on_aspect_ratio_change") do
|
|
390
|
+
require "gemba/settings_window"
|
|
391
|
+
received = nil
|
|
392
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
393
|
+
on_aspect_ratio_change: proc { |keep| received = keep }
|
|
394
|
+
})
|
|
395
|
+
sw.show
|
|
396
|
+
app.update
|
|
397
|
+
|
|
398
|
+
# Simulate user unchecking the checkbox
|
|
399
|
+
app.command(Gemba::SettingsWindow::ASPECT_CHECK, 'invoke')
|
|
400
|
+
app.update
|
|
401
|
+
|
|
402
|
+
assert_equal false, received
|
|
403
|
+
end
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
def test_checking_aspect_ratio_fires_callback
|
|
407
|
+
assert_tk_app("re-checking aspect ratio fires callback with true") do
|
|
408
|
+
require "gemba/settings_window"
|
|
409
|
+
received = nil
|
|
410
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
411
|
+
on_aspect_ratio_change: proc { |keep| received = keep }
|
|
412
|
+
})
|
|
413
|
+
sw.show
|
|
414
|
+
app.update
|
|
415
|
+
|
|
416
|
+
# Uncheck then re-check
|
|
417
|
+
app.command(Gemba::SettingsWindow::ASPECT_CHECK, 'invoke')
|
|
418
|
+
app.update
|
|
419
|
+
app.command(Gemba::SettingsWindow::ASPECT_CHECK, 'invoke')
|
|
420
|
+
app.update
|
|
421
|
+
|
|
422
|
+
assert_equal true, received
|
|
423
|
+
end
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
# -- Show FPS checkbox ----------------------------------------------------
|
|
427
|
+
|
|
428
|
+
def test_show_fps_defaults_to_on
|
|
429
|
+
assert_tk_app("show fps checkbox defaults to on") do
|
|
430
|
+
require "gemba/settings_window"
|
|
431
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
432
|
+
sw.show
|
|
433
|
+
app.update
|
|
434
|
+
|
|
435
|
+
assert_equal '1', app.get_variable(Gemba::SettingsWindow::VAR_SHOW_FPS)
|
|
436
|
+
end
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
def test_unchecking_show_fps_fires_callback
|
|
440
|
+
assert_tk_app("unchecking show fps fires on_show_fps_change") do
|
|
441
|
+
require "gemba/settings_window"
|
|
442
|
+
received = nil
|
|
443
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
444
|
+
on_show_fps_change: proc { |show| received = show }
|
|
445
|
+
})
|
|
446
|
+
sw.show
|
|
447
|
+
app.update
|
|
448
|
+
|
|
449
|
+
app.command(Gemba::SettingsWindow::SHOW_FPS_CHECK, 'invoke')
|
|
450
|
+
app.update
|
|
451
|
+
|
|
452
|
+
assert_equal false, received
|
|
453
|
+
end
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
# -- Keyboard mode --------------------------------------------------------
|
|
457
|
+
|
|
458
|
+
def test_starts_in_keyboard_mode
|
|
459
|
+
assert_tk_app("starts in keyboard mode") do
|
|
460
|
+
require "gemba/settings_window"
|
|
461
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
462
|
+
sw.show
|
|
463
|
+
app.update
|
|
464
|
+
|
|
465
|
+
assert sw.keyboard_mode?
|
|
466
|
+
end
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
def test_keyboard_mode_labels_show_keysyms
|
|
470
|
+
assert_tk_app("keyboard mode shows keysym labels") do
|
|
471
|
+
require "gemba/settings_window"
|
|
472
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
473
|
+
sw.show
|
|
474
|
+
app.update
|
|
475
|
+
|
|
476
|
+
text = app.command(Gemba::SettingsWindow::GP_BTN_A, 'cget', '-text')
|
|
477
|
+
assert_equal 'z', text
|
|
478
|
+
text = app.command(Gemba::SettingsWindow::GP_BTN_START, 'cget', '-text')
|
|
479
|
+
assert_equal 'Return', text
|
|
480
|
+
end
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
def test_switching_to_gamepad_mode_changes_labels
|
|
484
|
+
assert_tk_app("switching to gamepad shows gamepad labels") do
|
|
485
|
+
require "gemba/settings_window"
|
|
486
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
487
|
+
sw.show
|
|
488
|
+
app.update
|
|
489
|
+
|
|
490
|
+
sw.update_gamepad_list(['Keyboard Only', 'Test Gamepad'])
|
|
491
|
+
app.set_variable(Gemba::SettingsWindow::VAR_GAMEPAD, 'Test Gamepad')
|
|
492
|
+
app.command(:event, 'generate', Gemba::SettingsWindow::GAMEPAD_COMBO, '<<ComboboxSelected>>')
|
|
493
|
+
app.update
|
|
494
|
+
|
|
495
|
+
refute sw.keyboard_mode?
|
|
496
|
+
text = app.command(Gemba::SettingsWindow::GP_BTN_A, 'cget', '-text')
|
|
497
|
+
assert_equal 'a', text
|
|
498
|
+
text = app.command(Gemba::SettingsWindow::GP_BTN_START, 'cget', '-text')
|
|
499
|
+
assert_equal 'start', text
|
|
500
|
+
end
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
def test_deadzone_disabled_in_keyboard_mode
|
|
504
|
+
assert_tk_app("dead zone slider disabled in keyboard mode") do
|
|
505
|
+
require "gemba/settings_window"
|
|
506
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
507
|
+
sw.show
|
|
508
|
+
app.update
|
|
509
|
+
|
|
510
|
+
state = app.command(Gemba::SettingsWindow::DEADZONE_SCALE, 'cget', '-state')
|
|
511
|
+
assert_equal 'disabled', state
|
|
512
|
+
end
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
def test_deadzone_enabled_in_gamepad_mode
|
|
516
|
+
assert_tk_app("dead zone slider enabled in gamepad mode") do
|
|
517
|
+
require "gemba/settings_window"
|
|
518
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
519
|
+
sw.show
|
|
520
|
+
app.update
|
|
521
|
+
|
|
522
|
+
sw.update_gamepad_list(['Keyboard Only', 'Test Gamepad'])
|
|
523
|
+
app.set_variable(Gemba::SettingsWindow::VAR_GAMEPAD, 'Test Gamepad')
|
|
524
|
+
app.command(:event, 'generate', Gemba::SettingsWindow::GAMEPAD_COMBO, '<<ComboboxSelected>>')
|
|
525
|
+
app.update
|
|
526
|
+
|
|
527
|
+
state = app.command(Gemba::SettingsWindow::DEADZONE_SCALE, 'cget', '-state')
|
|
528
|
+
assert_equal 'normal', state
|
|
529
|
+
end
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
def test_keyboard_capture_fires_keyboard_callback
|
|
533
|
+
assert_tk_app("keyboard capture fires on_keyboard_map_change") do
|
|
534
|
+
require "gemba/settings_window"
|
|
535
|
+
received_gba = nil
|
|
536
|
+
received_key = nil
|
|
537
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
538
|
+
on_keyboard_map_change: proc { |g, k| received_gba = g; received_key = k }
|
|
539
|
+
})
|
|
540
|
+
sw.show
|
|
541
|
+
app.update
|
|
542
|
+
|
|
543
|
+
app.command(Gemba::SettingsWindow::GP_BTN_B, 'invoke')
|
|
544
|
+
app.update
|
|
545
|
+
sw.capture_mapping('space')
|
|
546
|
+
app.update
|
|
547
|
+
|
|
548
|
+
assert_equal :b, received_gba
|
|
549
|
+
assert_equal 'space', received_key
|
|
550
|
+
end
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
def test_switching_mode_cancels_listen
|
|
554
|
+
assert_tk_app("switching input mode cancels active listen") do
|
|
555
|
+
require "gemba/settings_window"
|
|
556
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
557
|
+
sw.show
|
|
558
|
+
app.update
|
|
559
|
+
|
|
560
|
+
# Start listening in keyboard mode
|
|
561
|
+
app.command(Gemba::SettingsWindow::GP_BTN_A, 'invoke')
|
|
562
|
+
app.update
|
|
563
|
+
assert_equal :a, sw.listening_for
|
|
564
|
+
|
|
565
|
+
# Switch to gamepad mode — should cancel listen
|
|
566
|
+
sw.update_gamepad_list(['Keyboard Only', 'Test Gamepad'])
|
|
567
|
+
app.set_variable(Gemba::SettingsWindow::VAR_GAMEPAD, 'Test Gamepad')
|
|
568
|
+
app.command(:event, 'generate', Gemba::SettingsWindow::GAMEPAD_COMBO, '<<ComboboxSelected>>')
|
|
569
|
+
app.update
|
|
570
|
+
|
|
571
|
+
assert_nil sw.listening_for
|
|
572
|
+
text = app.command(Gemba::SettingsWindow::GP_BTN_A, 'cget', '-text')
|
|
573
|
+
assert_equal 'a', text # reverted to gamepad default (not "Press...")
|
|
574
|
+
end
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
# -- Virtual gamepad integration ------------------------------------------
|
|
578
|
+
|
|
579
|
+
def test_virtual_gamepad_listen_and_capture
|
|
580
|
+
assert_tk_app("virtual gamepad button press captured in listen mode") do
|
|
581
|
+
require "gemba/settings_window"
|
|
582
|
+
require "teek/sdl2"
|
|
583
|
+
gp_cls = Teek::SDL2::Gamepad
|
|
584
|
+
|
|
585
|
+
gp_cls.init_subsystem
|
|
586
|
+
idx = gp_cls.attach_virtual
|
|
587
|
+
gp = gp_cls.open(idx)
|
|
588
|
+
|
|
589
|
+
received_gba = nil
|
|
590
|
+
received_gp = nil
|
|
591
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
592
|
+
on_gamepad_map_change: proc { |g, b| received_gba = g; received_gp = b }
|
|
593
|
+
})
|
|
594
|
+
sw.show
|
|
595
|
+
app.update
|
|
596
|
+
|
|
597
|
+
# Switch to gamepad mode (default is keyboard)
|
|
598
|
+
sw.update_gamepad_list(['Keyboard Only', gp.name])
|
|
599
|
+
app.set_variable(Gemba::SettingsWindow::VAR_GAMEPAD, gp.name)
|
|
600
|
+
app.command(:event, 'generate', Gemba::SettingsWindow::GAMEPAD_COMBO, '<<ComboboxSelected>>')
|
|
601
|
+
app.update
|
|
602
|
+
refute sw.keyboard_mode?
|
|
603
|
+
|
|
604
|
+
# Enter listen mode for B button
|
|
605
|
+
app.command(Gemba::SettingsWindow::GP_BTN_B, 'invoke')
|
|
606
|
+
app.update
|
|
607
|
+
assert_equal :b, sw.listening_for
|
|
608
|
+
|
|
609
|
+
# Press X on virtual gamepad
|
|
610
|
+
gp.set_virtual_button(:x, true)
|
|
611
|
+
gp_cls.poll_events
|
|
612
|
+
|
|
613
|
+
# Simulate what the player's probe timer does
|
|
614
|
+
gp_cls.buttons.each do |btn|
|
|
615
|
+
if gp.button?(btn)
|
|
616
|
+
sw.capture_mapping(btn)
|
|
617
|
+
break
|
|
618
|
+
end
|
|
619
|
+
end
|
|
620
|
+
app.update
|
|
621
|
+
|
|
622
|
+
assert_nil sw.listening_for
|
|
623
|
+
assert_equal :b, received_gba
|
|
624
|
+
assert_equal :x, received_gp
|
|
625
|
+
|
|
626
|
+
text = app.command(Gemba::SettingsWindow::GP_BTN_B, 'cget', '-text')
|
|
627
|
+
assert_equal 'x', text
|
|
628
|
+
|
|
629
|
+
gp.set_virtual_button(:x, false)
|
|
630
|
+
gp.close
|
|
631
|
+
gp_cls.detach_virtual
|
|
632
|
+
gp_cls.shutdown_subsystem
|
|
633
|
+
end
|
|
634
|
+
end
|
|
635
|
+
|
|
636
|
+
# -- Keyboard mapping conflict with hotkeys --------------------------------
|
|
637
|
+
|
|
638
|
+
def test_kb_mapping_rejected_when_conflicting_with_hotkey
|
|
639
|
+
assert_tk_app("keyboard mapping rejected when key conflicts with hotkey") do
|
|
640
|
+
require "gemba/settings_window"
|
|
641
|
+
require "gemba/hotkey_map"
|
|
642
|
+
received = false
|
|
643
|
+
conflict_msg = nil
|
|
644
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
645
|
+
on_keyboard_map_change: proc { |*| received = true },
|
|
646
|
+
on_validate_kb_mapping: ->(keysym) {
|
|
647
|
+
# Simulate: 'F5' is the Quick Save hotkey
|
|
648
|
+
keysym == 'F5' ? '"F5" is assigned to hotkey: Quick save' : nil
|
|
649
|
+
},
|
|
650
|
+
on_key_conflict: proc { |msg| conflict_msg = msg },
|
|
651
|
+
})
|
|
652
|
+
sw.show
|
|
653
|
+
app.update
|
|
654
|
+
|
|
655
|
+
# Try to bind GBA A to F5 (conflicts with hotkey)
|
|
656
|
+
app.command(Gemba::SettingsWindow::GP_BTN_A, 'invoke')
|
|
657
|
+
app.update
|
|
658
|
+
sw.capture_mapping('F5')
|
|
659
|
+
app.update
|
|
660
|
+
|
|
661
|
+
refute received, "on_keyboard_map_change should not fire for rejected key"
|
|
662
|
+
assert_equal '"F5" is assigned to hotkey: Quick save', conflict_msg
|
|
663
|
+
# Label should revert to original default
|
|
664
|
+
text = app.command(Gemba::SettingsWindow::GP_BTN_A, 'cget', '-text')
|
|
665
|
+
assert_equal 'z', text
|
|
666
|
+
assert_nil sw.listening_for
|
|
667
|
+
end
|
|
668
|
+
end
|
|
669
|
+
|
|
670
|
+
def test_kb_mapping_accepted_when_no_conflict
|
|
671
|
+
assert_tk_app("keyboard mapping accepted when no conflict") do
|
|
672
|
+
require "gemba/settings_window"
|
|
673
|
+
require "gemba/hotkey_map"
|
|
674
|
+
received_gba = nil
|
|
675
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
676
|
+
on_keyboard_map_change: proc { |g, _| received_gba = g },
|
|
677
|
+
on_validate_kb_mapping: ->(_) { nil },
|
|
678
|
+
})
|
|
679
|
+
sw.show
|
|
680
|
+
app.update
|
|
681
|
+
|
|
682
|
+
app.command(Gemba::SettingsWindow::GP_BTN_A, 'invoke')
|
|
683
|
+
app.update
|
|
684
|
+
sw.capture_mapping('m')
|
|
685
|
+
app.update
|
|
686
|
+
|
|
687
|
+
assert_equal :a, received_gba
|
|
688
|
+
text = app.command(Gemba::SettingsWindow::GP_BTN_A, 'cget', '-text')
|
|
689
|
+
assert_equal 'm', text
|
|
690
|
+
end
|
|
691
|
+
end
|
|
692
|
+
|
|
693
|
+
def test_gamepad_mapping_skips_validation
|
|
694
|
+
assert_tk_app("gamepad mode skips keyboard validation") do
|
|
695
|
+
require "gemba/settings_window"
|
|
696
|
+
require "gemba/hotkey_map"
|
|
697
|
+
require "teek/sdl2"
|
|
698
|
+
gp_cls = Teek::SDL2::Gamepad
|
|
699
|
+
gp_cls.init_subsystem
|
|
700
|
+
idx = gp_cls.attach_virtual
|
|
701
|
+
gp = gp_cls.open(idx)
|
|
702
|
+
|
|
703
|
+
received_gba = nil
|
|
704
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
705
|
+
on_gamepad_map_change: proc { |g, _| received_gba = g },
|
|
706
|
+
on_validate_kb_mapping: ->(_) { "should not be called" },
|
|
707
|
+
})
|
|
708
|
+
sw.show
|
|
709
|
+
app.update
|
|
710
|
+
|
|
711
|
+
# Switch to gamepad mode
|
|
712
|
+
sw.update_gamepad_list(['Keyboard Only', gp.name])
|
|
713
|
+
app.set_variable(Gemba::SettingsWindow::VAR_GAMEPAD, gp.name)
|
|
714
|
+
app.command(:event, 'generate', Gemba::SettingsWindow::GAMEPAD_COMBO, '<<ComboboxSelected>>')
|
|
715
|
+
app.update
|
|
716
|
+
|
|
717
|
+
# Gamepad capture — no keyboard validation applies
|
|
718
|
+
app.command(Gemba::SettingsWindow::GP_BTN_A, 'invoke')
|
|
719
|
+
app.update
|
|
720
|
+
sw.capture_mapping(:x)
|
|
721
|
+
app.update
|
|
722
|
+
|
|
723
|
+
assert_equal :a, received_gba
|
|
724
|
+
|
|
725
|
+
gp.close
|
|
726
|
+
gp_cls.detach_virtual
|
|
727
|
+
gp_cls.shutdown_subsystem
|
|
728
|
+
end
|
|
729
|
+
end
|
|
730
|
+
|
|
731
|
+
# -- Pixel filter combo ----------------------------------------------------
|
|
732
|
+
|
|
733
|
+
def test_pixel_filter_defaults_to_nearest
|
|
734
|
+
assert_tk_app("pixel filter defaults to Nearest Neighbor") do
|
|
735
|
+
require "gemba/settings_window"
|
|
736
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
737
|
+
sw.show
|
|
738
|
+
app.update
|
|
739
|
+
|
|
740
|
+
assert_equal 'Nearest Neighbor', app.get_variable(Gemba::SettingsWindow::VAR_FILTER)
|
|
741
|
+
end
|
|
742
|
+
end
|
|
743
|
+
|
|
744
|
+
def test_selecting_bilinear_fires_callback
|
|
745
|
+
assert_tk_app("selecting Bilinear fires on_filter_change") do
|
|
746
|
+
require "gemba/settings_window"
|
|
747
|
+
received = nil
|
|
748
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
749
|
+
on_filter_change: proc { |f| received = f }
|
|
750
|
+
})
|
|
751
|
+
sw.show
|
|
752
|
+
app.update
|
|
753
|
+
|
|
754
|
+
app.set_variable(Gemba::SettingsWindow::VAR_FILTER, 'Bilinear')
|
|
755
|
+
app.command(:event, 'generate', Gemba::SettingsWindow::FILTER_COMBO, '<<ComboboxSelected>>')
|
|
756
|
+
app.update
|
|
757
|
+
|
|
758
|
+
assert_equal 'linear', received
|
|
759
|
+
end
|
|
760
|
+
end
|
|
761
|
+
|
|
762
|
+
# -- Integer scaling checkbox ----------------------------------------------
|
|
763
|
+
|
|
764
|
+
def test_integer_scale_defaults_to_off
|
|
765
|
+
assert_tk_app("integer scale checkbox defaults to off") do
|
|
766
|
+
require "gemba/settings_window"
|
|
767
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
768
|
+
sw.show
|
|
769
|
+
app.update
|
|
770
|
+
|
|
771
|
+
assert_equal '0', app.get_variable(Gemba::SettingsWindow::VAR_INTEGER_SCALE)
|
|
772
|
+
end
|
|
773
|
+
end
|
|
774
|
+
|
|
775
|
+
def test_clicking_integer_scale_fires_callback
|
|
776
|
+
assert_tk_app("clicking integer scale fires on_integer_scale_change") do
|
|
777
|
+
require "gemba/settings_window"
|
|
778
|
+
received = nil
|
|
779
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
780
|
+
on_integer_scale_change: proc { |v| received = v }
|
|
781
|
+
})
|
|
782
|
+
sw.show
|
|
783
|
+
app.update
|
|
784
|
+
|
|
785
|
+
app.command(Gemba::SettingsWindow::INTEGER_SCALE_CHECK, 'invoke')
|
|
786
|
+
app.update
|
|
787
|
+
|
|
788
|
+
assert_equal true, received
|
|
789
|
+
end
|
|
790
|
+
end
|
|
791
|
+
|
|
792
|
+
# -- Color correction checkbox --------------------------------------------
|
|
793
|
+
|
|
794
|
+
def test_color_correction_defaults_to_off
|
|
795
|
+
assert_tk_app("color correction checkbox defaults to off") do
|
|
796
|
+
require "gemba/settings_window"
|
|
797
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
798
|
+
sw.show
|
|
799
|
+
app.update
|
|
800
|
+
|
|
801
|
+
assert_equal '0', app.get_variable(Gemba::SettingsWindow::VAR_COLOR_CORRECTION)
|
|
802
|
+
end
|
|
803
|
+
end
|
|
804
|
+
|
|
805
|
+
def test_clicking_color_correction_fires_callback
|
|
806
|
+
assert_tk_app("clicking color correction fires on_color_correction_change") do
|
|
807
|
+
require "gemba/settings_window"
|
|
808
|
+
received = nil
|
|
809
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
810
|
+
on_color_correction_change: proc { |v| received = v }
|
|
811
|
+
})
|
|
812
|
+
sw.show
|
|
813
|
+
app.update
|
|
814
|
+
|
|
815
|
+
app.command(Gemba::SettingsWindow::COLOR_CORRECTION_CHECK, 'invoke')
|
|
816
|
+
app.update
|
|
817
|
+
|
|
818
|
+
assert_equal true, received
|
|
819
|
+
end
|
|
820
|
+
end
|
|
821
|
+
|
|
822
|
+
def test_unchecking_color_correction_fires_false
|
|
823
|
+
assert_tk_app("unchecking color correction fires callback with false") do
|
|
824
|
+
require "gemba/settings_window"
|
|
825
|
+
received = nil
|
|
826
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
827
|
+
on_color_correction_change: proc { |v| received = v }
|
|
828
|
+
})
|
|
829
|
+
sw.show
|
|
830
|
+
app.update
|
|
831
|
+
|
|
832
|
+
# Check then uncheck
|
|
833
|
+
app.command(Gemba::SettingsWindow::COLOR_CORRECTION_CHECK, 'invoke')
|
|
834
|
+
app.update
|
|
835
|
+
app.command(Gemba::SettingsWindow::COLOR_CORRECTION_CHECK, 'invoke')
|
|
836
|
+
app.update
|
|
837
|
+
|
|
838
|
+
assert_equal false, received
|
|
839
|
+
end
|
|
840
|
+
end
|
|
841
|
+
|
|
842
|
+
# -- Frame blending checkbox -----------------------------------------------
|
|
843
|
+
|
|
844
|
+
def test_frame_blending_defaults_to_off
|
|
845
|
+
assert_tk_app("frame blending checkbox defaults to off") do
|
|
846
|
+
require "gemba/settings_window"
|
|
847
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
848
|
+
sw.show
|
|
849
|
+
app.update
|
|
850
|
+
|
|
851
|
+
assert_equal '0', app.get_variable(Gemba::SettingsWindow::VAR_FRAME_BLENDING)
|
|
852
|
+
end
|
|
853
|
+
end
|
|
854
|
+
|
|
855
|
+
def test_clicking_frame_blending_fires_callback
|
|
856
|
+
assert_tk_app("clicking frame blending fires on_frame_blending_change") do
|
|
857
|
+
require "gemba/settings_window"
|
|
858
|
+
received = nil
|
|
859
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
860
|
+
on_frame_blending_change: proc { |v| received = v }
|
|
861
|
+
})
|
|
862
|
+
sw.show
|
|
863
|
+
app.update
|
|
864
|
+
|
|
865
|
+
app.command(Gemba::SettingsWindow::FRAME_BLENDING_CHECK, 'invoke')
|
|
866
|
+
app.update
|
|
867
|
+
|
|
868
|
+
assert_equal true, received
|
|
869
|
+
end
|
|
870
|
+
end
|
|
871
|
+
|
|
872
|
+
def test_unchecking_frame_blending_fires_false
|
|
873
|
+
assert_tk_app("unchecking frame blending fires callback with false") do
|
|
874
|
+
require "gemba/settings_window"
|
|
875
|
+
received = nil
|
|
876
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
877
|
+
on_frame_blending_change: proc { |v| received = v }
|
|
878
|
+
})
|
|
879
|
+
sw.show
|
|
880
|
+
app.update
|
|
881
|
+
|
|
882
|
+
# Check then uncheck
|
|
883
|
+
app.command(Gemba::SettingsWindow::FRAME_BLENDING_CHECK, 'invoke')
|
|
884
|
+
app.update
|
|
885
|
+
app.command(Gemba::SettingsWindow::FRAME_BLENDING_CHECK, 'invoke')
|
|
886
|
+
app.update
|
|
887
|
+
|
|
888
|
+
assert_equal false, received
|
|
889
|
+
end
|
|
890
|
+
end
|
|
891
|
+
|
|
892
|
+
# -- Per-game settings checkbox -------------------------------------------
|
|
893
|
+
|
|
894
|
+
def test_per_game_checkbox_defaults_disabled
|
|
895
|
+
assert_tk_app("per-game checkbox defaults disabled") do
|
|
896
|
+
require "gemba/settings_window"
|
|
897
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
898
|
+
sw.show
|
|
899
|
+
app.update
|
|
900
|
+
|
|
901
|
+
state = app.command(Gemba::SettingsWindow::PER_GAME_CHECK, 'state')
|
|
902
|
+
assert_includes state, 'disabled'
|
|
903
|
+
end
|
|
904
|
+
end
|
|
905
|
+
|
|
906
|
+
def test_set_per_game_available_enables_checkbox
|
|
907
|
+
assert_tk_app("set_per_game_available enables checkbox") do
|
|
908
|
+
require "gemba/settings_window"
|
|
909
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
910
|
+
sw.show
|
|
911
|
+
app.update
|
|
912
|
+
|
|
913
|
+
sw.set_per_game_available(true)
|
|
914
|
+
app.update
|
|
915
|
+
|
|
916
|
+
state = app.command(Gemba::SettingsWindow::PER_GAME_CHECK, 'state')
|
|
917
|
+
refute_includes state, 'disabled'
|
|
918
|
+
end
|
|
919
|
+
end
|
|
920
|
+
|
|
921
|
+
def test_per_game_toggle_fires_callback
|
|
922
|
+
assert_tk_app("per-game toggle fires on_per_game_toggle") do
|
|
923
|
+
require "gemba/settings_window"
|
|
924
|
+
received = nil
|
|
925
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
926
|
+
on_per_game_toggle: proc { |v| received = v }
|
|
927
|
+
})
|
|
928
|
+
sw.show
|
|
929
|
+
app.update
|
|
930
|
+
|
|
931
|
+
sw.set_per_game_available(true)
|
|
932
|
+
app.update
|
|
933
|
+
app.command(Gemba::SettingsWindow::PER_GAME_CHECK, 'invoke')
|
|
934
|
+
app.update
|
|
935
|
+
|
|
936
|
+
assert_equal true, received
|
|
937
|
+
end
|
|
938
|
+
end
|
|
939
|
+
|
|
940
|
+
def test_set_per_game_active_syncs_variable
|
|
941
|
+
assert_tk_app("set_per_game_active syncs variable") do
|
|
942
|
+
require "gemba/settings_window"
|
|
943
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
944
|
+
sw.show
|
|
945
|
+
app.update
|
|
946
|
+
|
|
947
|
+
sw.set_per_game_active(true)
|
|
948
|
+
assert_equal '1', app.get_variable(Gemba::SettingsWindow::VAR_PER_GAME)
|
|
949
|
+
|
|
950
|
+
sw.set_per_game_active(false)
|
|
951
|
+
assert_equal '0', app.get_variable(Gemba::SettingsWindow::VAR_PER_GAME)
|
|
952
|
+
end
|
|
953
|
+
end
|
|
954
|
+
|
|
955
|
+
def test_per_game_disabled_on_gamepad_tab
|
|
956
|
+
assert_tk_app("per-game disabled on gamepad tab") do
|
|
957
|
+
require "gemba/settings_window"
|
|
958
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
959
|
+
sw.show
|
|
960
|
+
app.update
|
|
961
|
+
|
|
962
|
+
# Enable per-game (simulating ROM loaded)
|
|
963
|
+
sw.set_per_game_available(true)
|
|
964
|
+
app.update
|
|
965
|
+
|
|
966
|
+
# Switch to gamepad tab — checkbox should become disabled
|
|
967
|
+
app.command(Gemba::SettingsWindow::NB, 'select', Gemba::SettingsWindow::GAMEPAD_TAB)
|
|
968
|
+
app.update
|
|
969
|
+
|
|
970
|
+
state = app.command(Gemba::SettingsWindow::PER_GAME_CHECK, 'state')
|
|
971
|
+
assert_includes state, 'disabled', "Per-game checkbox should be disabled on gamepad tab"
|
|
972
|
+
end
|
|
973
|
+
end
|
|
974
|
+
|
|
975
|
+
def test_per_game_re_enabled_on_video_tab
|
|
976
|
+
assert_tk_app("per-game re-enabled on video tab") do
|
|
977
|
+
require "gemba/settings_window"
|
|
978
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
979
|
+
sw.show
|
|
980
|
+
app.update
|
|
981
|
+
|
|
982
|
+
sw.set_per_game_available(true)
|
|
983
|
+
app.update
|
|
984
|
+
|
|
985
|
+
# Switch to gamepad (disables), then back to video (re-enables)
|
|
986
|
+
app.command(Gemba::SettingsWindow::NB, 'select', Gemba::SettingsWindow::GAMEPAD_TAB)
|
|
987
|
+
app.update
|
|
988
|
+
app.command(Gemba::SettingsWindow::NB, 'select', "#{Gemba::SettingsWindow::NB}.video")
|
|
989
|
+
app.update
|
|
990
|
+
|
|
991
|
+
state = app.command(Gemba::SettingsWindow::PER_GAME_CHECK, 'state')
|
|
992
|
+
refute_includes state, 'disabled', "Per-game checkbox should be enabled on video tab"
|
|
993
|
+
end
|
|
994
|
+
end
|
|
995
|
+
|
|
996
|
+
# -- Recording tab -------------------------------------------------------
|
|
997
|
+
|
|
998
|
+
def test_recording_tab_exists
|
|
999
|
+
assert_tk_app("recording tab exists in notebook") do
|
|
1000
|
+
require "gemba/settings_window"
|
|
1001
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
1002
|
+
sw.show
|
|
1003
|
+
app.update
|
|
1004
|
+
|
|
1005
|
+
tabs = app.command(Gemba::SettingsWindow::NB, 'tabs')
|
|
1006
|
+
assert_includes tabs, Gemba::SettingsWindow::REC_TAB
|
|
1007
|
+
end
|
|
1008
|
+
end
|
|
1009
|
+
|
|
1010
|
+
def test_compression_combobox_defaults_to_1
|
|
1011
|
+
assert_tk_app("compression combobox defaults to 1") do
|
|
1012
|
+
require "gemba/settings_window"
|
|
1013
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {})
|
|
1014
|
+
sw.show
|
|
1015
|
+
app.update
|
|
1016
|
+
|
|
1017
|
+
assert_equal '1', app.get_variable(Gemba::SettingsWindow::VAR_REC_COMPRESSION)
|
|
1018
|
+
end
|
|
1019
|
+
end
|
|
1020
|
+
|
|
1021
|
+
def test_selecting_compression_fires_callback
|
|
1022
|
+
assert_tk_app("selecting compression fires on_compression_change") do
|
|
1023
|
+
require "gemba/settings_window"
|
|
1024
|
+
received = nil
|
|
1025
|
+
sw = Gemba::SettingsWindow.new(app, callbacks: {
|
|
1026
|
+
on_compression_change: proc { |v| received = v }
|
|
1027
|
+
})
|
|
1028
|
+
sw.show
|
|
1029
|
+
app.update
|
|
1030
|
+
|
|
1031
|
+
app.set_variable(Gemba::SettingsWindow::VAR_REC_COMPRESSION, '6')
|
|
1032
|
+
app.command(:event, 'generate', Gemba::SettingsWindow::REC_COMPRESSION_COMBO, '<<ComboboxSelected>>')
|
|
1033
|
+
app.update
|
|
1034
|
+
|
|
1035
|
+
assert_equal 6, received
|
|
1036
|
+
end
|
|
1037
|
+
end
|
|
1038
|
+
|
|
1039
|
+
end
|