rb_sdl2 0.1.0 → 0.2.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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +69 -0
  3. data/README.md +15 -1
  4. data/lib/rb_sdl2/audio/audio.rb +162 -0
  5. data/lib/rb_sdl2/audio/audio_buffer.rb +12 -19
  6. data/lib/rb_sdl2/audio/audio_device.rb +17 -23
  7. data/lib/rb_sdl2/audio/audio_spec.rb +38 -6
  8. data/lib/rb_sdl2/audio/audio_spec_reader.rb +10 -0
  9. data/lib/rb_sdl2/clipboard.rb +31 -31
  10. data/lib/rb_sdl2/cpu_info.rb +34 -17
  11. data/lib/rb_sdl2/cursor.rb +105 -24
  12. data/lib/rb_sdl2/display.rb +16 -16
  13. data/lib/rb_sdl2/display_mode.rb +1 -1
  14. data/lib/rb_sdl2/error.rb +14 -3
  15. data/lib/rb_sdl2/errors.rb +7 -0
  16. data/lib/rb_sdl2/event/event.rb +130 -0
  17. data/lib/rb_sdl2/event/event_filter.rb +34 -70
  18. data/lib/rb_sdl2/event/event_pointer.rb +26 -0
  19. data/lib/rb_sdl2/event/event_queue.rb +97 -120
  20. data/lib/rb_sdl2/event/event_type.rb +147 -205
  21. data/lib/rb_sdl2/filesystem.rb +8 -9
  22. data/lib/rb_sdl2/hint.rb +26 -24
  23. data/lib/rb_sdl2/keyboard/keyboard.rb +50 -0
  24. data/lib/rb_sdl2/keyboard/mod_state.rb +68 -0
  25. data/lib/rb_sdl2/keyboard/state.rb +39 -0
  26. data/lib/rb_sdl2/message_box.rb +69 -102
  27. data/lib/rb_sdl2/mouse/global_mouse.rb +10 -3
  28. data/lib/rb_sdl2/mouse/mouse.rb +64 -0
  29. data/lib/rb_sdl2/mouse/mouse_button.rb +13 -11
  30. data/lib/rb_sdl2/mouse/mouse_class.rb +9 -17
  31. data/lib/rb_sdl2/mouse/mouse_wheel.rb +21 -37
  32. data/lib/rb_sdl2/mouse/relative_mouse.rb +15 -1
  33. data/lib/rb_sdl2/palette.rb +15 -11
  34. data/lib/rb_sdl2/pixel_format_enum.rb +87 -55
  35. data/lib/rb_sdl2/platform.rb +3 -1
  36. data/lib/rb_sdl2/power_info.rb +34 -23
  37. data/lib/rb_sdl2/rect.rb +7 -1
  38. data/lib/rb_sdl2/ref_count_pointer.rb +25 -10
  39. data/lib/rb_sdl2/rw_ops/rw_file.rb +19 -0
  40. data/lib/rb_sdl2/rw_ops/rw_memory.rb +18 -0
  41. data/lib/rb_sdl2/rw_ops/rw_object.rb +126 -0
  42. data/lib/rb_sdl2/rw_ops/rw_ops.rb +104 -0
  43. data/lib/rb_sdl2/rw_ops/rw_ops_pointer.rb +14 -0
  44. data/lib/rb_sdl2/sdl.rb +72 -21
  45. data/lib/rb_sdl2/sdl_pointer.rb +22 -0
  46. data/lib/rb_sdl2/surface/blend_mode.rb +41 -41
  47. data/lib/rb_sdl2/surface/pixel_format.rb +34 -33
  48. data/lib/rb_sdl2/surface.rb +280 -244
  49. data/lib/rb_sdl2/text_input.rb +21 -15
  50. data/lib/rb_sdl2/timer.rb +36 -22
  51. data/lib/rb_sdl2/version.rb +5 -3
  52. data/lib/rb_sdl2/video.rb +17 -5
  53. data/lib/rb_sdl2/window/accessor.rb +135 -0
  54. data/lib/rb_sdl2/window/display.rb +8 -8
  55. data/lib/rb_sdl2/window/flash.rb +22 -0
  56. data/lib/rb_sdl2/window/hit_test.rb +22 -43
  57. data/lib/rb_sdl2/window/shape.rb +55 -40
  58. data/lib/rb_sdl2/window/state.rb +178 -0
  59. data/lib/rb_sdl2/window/window.rb +149 -0
  60. data/lib/rb_sdl2.rb +79 -17
  61. data/rb_sdl2.gemspec +12 -4
  62. metadata +38 -37
  63. data/lib/rb_sdl2/audio/audio_allowed_changes.rb +0 -17
  64. data/lib/rb_sdl2/audio/audio_format.rb +0 -23
  65. data/lib/rb_sdl2/audio.rb +0 -132
  66. data/lib/rb_sdl2/cursor/color_cursor.rb +0 -19
  67. data/lib/rb_sdl2/cursor/cursor_class.rb +0 -24
  68. data/lib/rb_sdl2/cursor/cursor_pointer.rb +0 -12
  69. data/lib/rb_sdl2/cursor/default_cursor.rb +0 -18
  70. data/lib/rb_sdl2/cursor/system_cursor.rb +0 -45
  71. data/lib/rb_sdl2/event.rb +0 -161
  72. data/lib/rb_sdl2/keyboard/key_mod.rb +0 -37
  73. data/lib/rb_sdl2/keyboard/keyboard_state.rb +0 -34
  74. data/lib/rb_sdl2/keyboard.rb +0 -50
  75. data/lib/rb_sdl2/mouse/window_mouse.rb +0 -17
  76. data/lib/rb_sdl2/mouse.rb +0 -74
  77. data/lib/rb_sdl2/rw_ops/rw_operator.rb +0 -102
  78. data/lib/rb_sdl2/rw_ops.rb +0 -124
  79. data/lib/rb_sdl2/screen_saver.rb +0 -11
  80. data/lib/rb_sdl2/window/dialog.rb +0 -19
  81. data/lib/rb_sdl2/window/grab.rb +0 -23
  82. data/lib/rb_sdl2/window/position.rb +0 -38
  83. data/lib/rb_sdl2/window/size.rb +0 -59
  84. data/lib/rb_sdl2/window/window_flags.rb +0 -78
  85. data/lib/rb_sdl2/window.rb +0 -242
@@ -1,16 +1,17 @@
1
1
  module RbSDL2
2
2
  module Filesystem
3
3
  class << self
4
+ require_relative 'sdl_pointer'
5
+
4
6
  # RbSDL2 にロードされた SDL2 の配置パスを戻す。
5
7
  # パスの末尾にはパスの区切り文字がかならずある。
6
8
  # パスの区切り記号は環境依存である。Windows であれば "\" が使われる。
7
9
  # Ruby は環境依存のパスの区切り文字を正しく取り扱うことができる。
8
10
  def base_path
9
- ptr = ::SDL2.SDL_GetBasePath
11
+ # 戻り値のポインターはアプリケーション側で開放する。
12
+ ptr = SDLPointer.new(::SDL.GetBasePath)
10
13
  raise RbSDL2Error if ptr.null?
11
- ptr.read_string.force_encoding(Encoding::UTF_8)
12
- ensure
13
- ::SDL2.SDL_free(ptr)
14
+ ptr.to_s
14
15
  end
15
16
 
16
17
  # アプリケーションが書き込むことのできるパスを戻す。
@@ -28,12 +29,10 @@ module RbSDL2
28
29
  # SDL が知りたいことはアプリケーションがアクセス可能かどうかだけだ。
29
30
  # エラーが出るかどうかはユーザが設定するパスのアクセス制限による。
30
31
  def pref_path(org_name, app_name)
31
- ptr = ::SDL2.SDL_GetPrefPath(org_name.encode(Encoding::UTF_8),
32
- app_name.encode(Encoding::UTF_8))
32
+ # 戻り値のポインターはアプリケーション側で開放する。
33
+ ptr = SDLPointer.new(::SDL.GetPrefPath(SDL.str_to_sdl(org_name), SDL.str_to_sdl(app_name)))
33
34
  raise RbSDL2Error if ptr.null?
34
- ptr.read_string.force_encoding(Encoding::UTF_8)
35
- ensure
36
- ::SDL2.SDL_free(ptr)
35
+ ptr.to_s
37
36
  end
38
37
  end
39
38
  end
data/lib/rb_sdl2/hint.rb CHANGED
@@ -1,24 +1,26 @@
1
- module RbSDL2
2
- module Hint
3
- class << self
4
- def [](name)
5
- ptr = ::SDL2.SDL_GetHint(name.to_s)
6
- ptr.null? ? nil : ptr.read_string
7
- end
8
-
9
- def []=(name, value)
10
- bool = ::SDL2.SDL_SetHintWithPriority(name.to_s, value&.to_s, ::SDL2::SDL_HINT_OVERRIDE)
11
- raise RbSDL2Error, "failed to set hint" if bool == ::SDL2::SDL_FALSE
12
- end
13
-
14
- def clear = ::SDL2.SDL_ClearHints
15
-
16
- def freeze = raise(TypeError, "cannot freeze Hint")
17
-
18
- def include?(name) = ::SDL2.SDL_GetHintBoolean(name, -1) != -1
19
- alias has_key? include?
20
- alias member? include?
21
- alias key? include?
22
- end
23
- end
24
- end
1
+ module RbSDL2
2
+ module Hint
3
+ class << self
4
+ # ヒントの設定が行われていないときは nil を戻す。
5
+ # SDL のデフォルト値はハードコーディングされているためこのメソッドで読み出すことはできない。
6
+ def [](name)
7
+ ptr = ::SDL.GetHint(name.to_s)
8
+ ptr.null? ? nil : ptr.read_string
9
+ end
10
+
11
+ def []=(name, value)
12
+ bool = ::SDL.SetHintWithPriority(name.to_s, value&.to_s, ::SDL::HINT_OVERRIDE)
13
+ raise RbSDL2Error, "failed to set hint" if bool == ::SDL::FALSE
14
+ end
15
+
16
+ def clear = ::SDL.ClearHints
17
+
18
+ def freeze = raise(TypeError, "cannot freeze Hint")
19
+
20
+ def include?(name) = ::SDL.GetHintBoolean(name, -1) != -1
21
+ alias has_key? include?
22
+ alias member? include?
23
+ alias key? include?
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,50 @@
1
+ module RbSDL2
2
+ module Keyboard
3
+ require_relative 'mod_state'
4
+ extend ModState
5
+
6
+ class << self
7
+ # いずれかのキーが押されている場合に true を戻す。つまり *any key* が押されたということ。
8
+ # このメソッドを使用するには定期的に Event.pump を呼び出してキーボード状態を更新する必要があります。
9
+ def any_key? = state.any?
10
+ alias hit_any_key? any_key?
11
+ alias pressed_any_key? any_key?
12
+
13
+ # s に与えた文字列に対応するスキャンコードのキーが押されてい場合に true を戻します。
14
+ # キーが押されていない場合、対応するスキャンコードが無い場合は false を戻します。
15
+ # このメソッドを使用するには定期的に Event.pump を呼び出してキーボード状態を更新する必要があります。
16
+ def key?(s) = state[::SDL.GetScancodeFromName(s)]
17
+ alias pressed_key? key?
18
+
19
+ # num に与えたキーコードに対応する文字列を戻します。対応する文字列が無い場合は nil を戻します。
20
+ def keycode_name(num) = (s = ::SDL.GetKeyName(num).read_string).empty? ? nil : s
21
+
22
+ # キーコードをスキャンコードに変換します。対応するキーコードがない場合は nil を戻します。
23
+ def keycode_to_scancode(num) = ::SDL.GetScancodeFromKey(num).nonzero?
24
+
25
+ # 現在キーボードの押されているキーの名前を配列で戻します。
26
+ # このメソッドを使用するには定期的に Event.pump を呼び出してキーボード状態を更新する必要があります。
27
+ def pressed_keys = state.to_a.map { |n| Keyboard.scancode_name(n) }
28
+
29
+ # num に与えたスキャンコードに対応する文字列を戻します。対応する文字列が無い場合は nil を戻します。
30
+ def scancode_name(num) = (s = ::SDL.GetScancodeName(num).read_string).empty? ? nil : s
31
+
32
+ # num に与えたスキャンコードのキーが押されている場合に true を戻します。
33
+ # スキャンコードに対応するキーがない場合、キーが押されていない場合は false を戻します。
34
+ def scancode?(num) = state.scancode?(num)
35
+
36
+ # スキャンコードをキーコードに変換します。対応するキーコードがない場合は nil を戻します。
37
+ def scancode_to_keycode(num) = ::SDL.GetKeyFromScancode(num).nonzero?
38
+
39
+ require_relative 'state'
40
+
41
+ def state = State.instance
42
+
43
+ # s に与えた文字列に対応するキーコードを戻します。対応するキーコードがない場合は nil を戻します。
44
+ def to_keycode(s) = ::SDL.GetKeyFromName(s).nonzero?
45
+
46
+ # s に与えた文字列に対応するスキャンコードを戻します。対応するスキャンコードが無い場合は nil を戻します。
47
+ def to_scancode(s) = ::SDL.GetScancodeFromName(s).nonzero?
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,68 @@
1
+ module RbSDL2
2
+ module Keyboard
3
+ module ModState
4
+ class << self
5
+ def state = ::SDL.GetModState
6
+
7
+ def state?(num) = state & num != 0
8
+
9
+ def state=(num)
10
+ ::SDL::SetModState(num)
11
+ end
12
+ end
13
+
14
+ KMOD_NONE = 0x0000
15
+ KMOD_LSHIFT = 0x0001
16
+ KMOD_RSHIFT = 0x0002
17
+ KMOD_LCTRL = 0x0040
18
+ KMOD_RCTRL = 0x0080
19
+ KMOD_LALT = 0x0100
20
+ KMOD_RALT = 0x0200
21
+ KMOD_LGUI = 0x0400
22
+ KMOD_RGUI = 0x0800
23
+ KMOD_NUM = 0x1000
24
+ KMOD_CAPS = 0x2000
25
+ KMOD_MODE = 0x4000
26
+ KMOD_SCROLL = 0x8000
27
+
28
+ KMOD_CTRL = KMOD_LCTRL | KMOD_RCTRL
29
+ KMOD_SHIFT = KMOD_LSHIFT | KMOD_RSHIFT
30
+ KMOD_ALT = KMOD_LALT | KMOD_RALT
31
+ KMOD_GUI = KMOD_LGUI | KMOD_RGUI
32
+
33
+ def alt_key? = ModState.state?(KMOD_ALT)
34
+
35
+ def caps_key? = ModState.state?(KMOD_CAPS)
36
+
37
+ def ctrl_key? = ModState.state?(KMOD_CTRL)
38
+
39
+ def gui_key? = ModState.state?(KMOD_GUI)
40
+
41
+ def l_alt_key? = ModState.state?(KMOD_LALT)
42
+
43
+ def l_ctrl_key? = ModState.state?(KMOD_LCTRL)
44
+
45
+ def l_gui_key? = ModState.state?(KMOD_LGUI)
46
+
47
+ def l_shift_key? = ModState.state?(KMOD_LSHIFT)
48
+
49
+ def mod_key? = ModState.state != 0
50
+
51
+ def mode_key? = ModState.state?(KMOD_MODE)
52
+
53
+ def num_key? = ModState.state?(KMOD_NUM)
54
+
55
+ def r_alt_key? = ModState.state?(KMOD_RALT)
56
+
57
+ def r_ctrl_key? = ModState.state?(KMOD_RCTRL)
58
+
59
+ def r_gui_key? = ModState.state?(KMOD_RGUI)
60
+
61
+ def r_shift_key? = ModState.state?(KMOD_RSHIFT)
62
+
63
+ def scroll_lock_key? = ModState.state?(KMOD_SCROLL)
64
+
65
+ def shift_key? = ModState.state?(KMOD_SHIFT)
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,39 @@
1
+ module RbSDL2
2
+ module Keyboard
3
+ # SDL 内部にあるキーボードのキースイッチング配列へアクセスします。
4
+ # キースイッチング状態は SDL_PumpEvents() が呼び出さられたときに更新されます。
5
+ class State
6
+ require 'singleton'
7
+ include Singleton
8
+
9
+ # SDL ロード前に呼び出すとエラーになる。その際にインスタンスは作成されない。
10
+ def initialize
11
+ num_keys = ::FFI::MemoryPointer.new(:int)
12
+ # SDL_GetKeyboardState() が戻すポインターは SDL がロードされた時点で作成されるため不変と考えてよい。
13
+ # この関数は SDL_Init() より前に呼ぶことができる。
14
+ # 引数に NULL ポインターを与えた場合にエラーを戻す。
15
+ @ptr = ::SDL.GetKeyboardState(num_keys)
16
+ raise RbSDL2Error if @ptr.null?
17
+ @size = num_keys.read_int
18
+ end
19
+
20
+ # nth に該当するスキャンコードのキーが押されているか調べます。
21
+ # nth のキーが押されている場合に nth を戻します。
22
+ # nth のキーが押されていない、nth が範囲外の場合は nil を戻します。
23
+ def [](nth) = 0 <= nth && nth < size && @ptr[nth].read_uint8 == ::SDL::PRESSED ? nth : nil
24
+ alias scancode? []
25
+
26
+ def any? = to_str.bytes.any? { |n| n == ::SDL::PRESSED }
27
+
28
+ def each = block_given? ? size.times { |i| yield(self[i]) } : to_enum
29
+
30
+ attr_reader :size
31
+ alias length size
32
+
33
+ def to_str = @ptr.read_bytes(size)
34
+
35
+ # 現在キーボードの押されている全てのキーに対応するスキャンコードを配列で戻します。
36
+ def to_a = to_str.bytes.with_index.inject([]) { |a, (n, i)| n == ::SDL::PRESSED ? a << i : a }
37
+ end
38
+ end
39
+ end
@@ -1,120 +1,87 @@
1
1
  module RbSDL2
2
2
  module MessageBox
3
- class MessageBoxButtonDataArray
4
- def initialize(num)
5
- @entity_class = ::SDL2::SDL_MessageBoxButtonData
6
- @ptr = ::FFI::MemoryPointer.new(@entity_class.size, num)
7
- end
3
+ ERROR = ::SDL::MESSAGEBOX_ERROR
4
+ WARN = ::SDL::MESSAGEBOX_WARNING
5
+ INFO = ::SDL::MESSAGEBOX_INFORMATION
8
6
 
9
- def [](nth) = @entity_class.new(@ptr + @entity_class.size * nth)
7
+ class << self
8
+ # 簡単なボタン入力のあるウィンドウを表示します。
9
+ # SDL が初期化される前に呼び出すことができます。
10
+ # 環境によってはこのメソッドをメインスレッドで呼び出す必要があるでしょう。
11
+ # このウィンドウを表示中はアプリケーションはブロックされます。
12
+ # ボタン配置は右詰めです。配列の先頭のボタン番号 0 がウィンドウ右側に配置され、以降はその左に配置されます。
13
+ #
14
+ # level: RbSDL2::MessageBox にある ERROR, WARN, INFO, 0 のどれかを与えます。
15
+ # これはウィンドウの本文部分に表示するアイコンを選択します。
16
+ # message:
17
+ # ウィンドウに表示する本文の文字列を与えます。
18
+ # オブジェクトを与えた場合はメソッド内部で文字列への変換を試みます。
19
+ # title:
20
+ # ウィンドウに表示するタイトルの文字列を与えます。
21
+ # オブジェクトを与えた場合はメソッド内部で文字列への変換を試みます。
22
+ # window:
23
+ # 関連のある親ウィンドウがあればそれを与えます。
24
+ # メッセージウィンドウが閉じるまで親ウィンドウは入力を受け付けなくなります。
25
+ # buttons:
26
+ # ボタンに表示する文字列または文字列の配列です。
27
+ # オブジェクトを与えた場合はメソッド内部で配列への変換を試みます。
28
+ # 配列の要素がオブジェクトの場合はメソッド内部で文字列への変換を試みます。
29
+ # nil を与えた場合はボタンが表示されません。
30
+ # その場合はユーザがエスケープキーを押さない限りこのメソッドを終了できません。
31
+ # default:
32
+ # 選択済みのボタンをボタン番号(0 から始まる)指定します。nil の場合はどのボタンも選択されません。
33
+ # ウィンドウ表示中にユーザがリターンキーを押すと選択済みのボタンが押されたことになります。
34
+ #
35
+ # 戻り値は押されたボタン番号か nil です。
36
+ # nil になる場合はこのウィンドウがアクティブな時に表示中にエスケープキーが押された場合です。
37
+ def show(level, message = nil, title = nil, window = nil, buttons: nil, default: nil)
38
+ # アンダーバーのついた変数はオブジェクトをスコープ中に保持するためにある。
39
+ data = ::SDL::MessageBoxData.new
40
+ data[:flags] = level
41
+ data[:window] = _window = window
42
+ data[:title] = _title = ::FFI::MemoryPointer.from_string(SDL.str_to_sdl(title))
43
+ data[:message] = _message = ::FFI::MemoryPointer.from_string(SDL.str_to_sdl(message))
10
44
 
11
- def to_ptr = @ptr
12
- end
45
+ texts = Array(buttons)
13
46
 
14
- class MessageBoxData
15
- def initialize(buttons: nil, colors: nil, escape_key: nil, level: nil, message: nil,
16
- return_key: nil, title: nil, window: nil)
17
- @st = ::SDL2::SDL_MessageBoxData.new.tap do |data|
18
- button_data = *buttons
19
- data[:numbuttons] = num_buttons = button_data.length
20
- data[:buttons] = @buttons = num_buttons.nonzero? &&
21
- MessageBoxButtonDataArray.new(num_buttons).tap do |data_ary|
22
- @button_texts = []
23
- num_buttons.times do |idx|
24
- st, (text, *) = data_ary[idx], button_data[idx]
25
- st[:buttonid] = idx
26
- st[:flags] = case idx
27
- when escape_key then ::SDL2::SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT
28
- when return_key then ::SDL2::SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT
29
- else 0
30
- end
31
- st[:text] = @button_texts[idx] =
32
- ::FFI::MemoryPointer.from_string(text.to_s.encode(Encoding::UTF_8))
33
- end
34
- end
35
- data[:colorScheme] = @color_scheme = colors &&
36
- ::SDL2::SDL_MessageBoxColorScheme.new.tap do |st|
37
- # r, g, b, a 形式だった場合にエラーを出さない。
38
- st[:colors].each.with_index { |c, i| c[:r], c[:g], c[:b] = colors[i] }
39
- end
40
- data[:flags] = MessageBoxFlags.to_num(level)
41
- data[:message] = @message =
42
- ::FFI::MemoryPointer.from_string(message.to_s.encode(Encoding::UTF_8))
43
- data[:title] = @title =
44
- ::FFI::MemoryPointer.from_string(title.to_s.encode(Encoding::UTF_8))
45
- data[:window] = window
46
- end
47
- end
47
+ data[:numbuttons] = num_buttons = texts.size
48
48
 
49
- def to_ptr = @st.to_ptr
50
- end
49
+ _texts = Array.new(num_buttons)
50
+ button_data = ::SDL::MessageBoxButtonData
51
+ st_size = button_data.size
51
52
 
52
- module MessageBoxFlags
53
- class << self
54
- def to_num(obj)
55
- case obj
56
- when /\Aerror/ then ::SDL2::SDL_MESSAGEBOX_ERROR
57
- when /\Ainfo/ then ::SDL2::SDL_MESSAGEBOX_INFORMATION
58
- when /\Awarn/ then ::SDL2::SDL_MESSAGEBOX_WARNING
59
- when nil then 0
60
- else
61
- raise ArgumentError
53
+ data[:buttons] = _buttons = ::FFI::MemoryPointer.new(st_size, num_buttons).tap do |ptr|
54
+ texts.each_with_index do |text, idx|
55
+ st = button_data.new(ptr + st_size * idx)
56
+ # Escape キー(SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT)はボタンへ割り当てない。
57
+ # return_key escape_key は排他的でありが同一値の場合はどちらかが機能しないため。
58
+ st[:flags] = idx == default ? ::SDL::MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT : 0
59
+ st[:buttonid] = idx
60
+ st[:text] = _texts[idx] = ::FFI::MemoryPointer.from_string(SDL.str_to_sdl(text))
61
+ st
62
62
  end
63
63
  end
64
- end
65
- end
66
-
67
- CONFIRMATION_OPTIONS = { buttons: { Cancel: false, OK: true }, default: true }.freeze
64
+ # colorScheme は環境依存。例えば Windows では反映されない。NULL の場合はシステム設定のカラーを使用する。
65
+ data[:colorScheme] = nil
68
66
 
69
- class << self
70
- def alert(msg = nil, window = nil, level: nil, message: msg, title: nil)
71
- err = ::SDL2.SDL_ShowSimpleMessageBox(MessageBoxFlags.to_num(level),
72
- title&.to_s&.encode(Encoding::UTF_8),
73
- message&.to_s&.encode(Encoding::UTF_8),
74
- window)
75
- raise RbSDL2Error if err < 0
76
- end
77
-
78
- def confirm(*args, **opts) = dialog(*args, **opts.merge!(CONFIRMATION_OPTIONS))
79
-
80
- # buttons: "label" | ["label",...] | [["label", obj],...] | {"label" => obj,...}
81
- # buttons 1個以上のオブジェクトがあること。0個の場合はエラーになる。
82
- # colors: [[r,g,b],...] | nil
83
- # 環境(例えば Win10)によっては colors は反映されない。 nil の場合はシステム設定のカラーが使用される。
84
- # ユーザがクリックしたボタンに応じたオブジェクトが戻る。
85
- # ユーザが Escape キーが押した場合(何も選択しなかった場合)ブロックが与えられていればブロックの評価内容が、
86
- # ブロックがなければ nil が戻る。
87
- def dialog(msg = nil, window = nil, buttons:, message: msg, **opts)
88
- button_data = *buttons
89
- raise ArgumentError if button_data.empty?
90
- # Escape キーの割り当ては可能だが行わないようにした。
91
- # Return キーと Escape キーの割り当てが同じ場合に Return キーは機能しなくなる。
92
- if opts.key?(:default)
93
- opts.merge!(return_key: button_data.index { |*, obj| obj == opts[:default] })
94
- opts.delete(:default)
95
- end
96
67
  ptr = ::FFI::MemoryPointer.new(:int)
97
- data = MessageBoxData.new(buttons: button_data, message: message, window: window, **opts)
98
- err = ::SDL2.SDL_ShowMessageBox(data, ptr)
68
+ err = ::SDL.ShowMessageBox(data, ptr)
99
69
  raise RbSDL2Error if err < 0
70
+ num = ptr.read_int
100
71
  # (Escape キーの割り当てがない場合に) Escape キーが押された場合 idx = -1
101
- if (idx = ptr.read_int) < 0
102
- block_given? ? yield : nil
103
- else
104
- button_data[idx]
105
- end
72
+ num if num >= 0
106
73
  end
107
74
 
108
- def error(*args, title: :Error, **opts)
109
- alert(*args, title: title, **opts.merge!(level: :error))
110
- end
111
-
112
- def info(*args, title: :Information, **opts)
113
- alert(*args, title: title, **opts.merge!(level: :info))
114
- end
115
-
116
- def warn(*args, title: :Warning, **opts)
117
- alert(*args, title: title, **opts.merge!(level: :warn))
75
+ # シンプルなメッセージウィンドウを開きます。
76
+ # MessageBox.show の簡易版です。ボタン一つのウィンドウが表示されます。
77
+ # 戻り値は常に true です。
78
+ def simple(level, message = nil, title = nil, window = nil)
79
+ err = ::SDL.ShowSimpleMessageBox(level,
80
+ SDL.str_to_sdl(title),
81
+ SDL.str_to_sdl(message),
82
+ window)
83
+ raise RbSDL2Error if err < 0
84
+ true
118
85
  end
119
86
  end
120
87
  end
@@ -3,14 +3,21 @@ module RbSDL2
3
3
  require_relative 'mouse_class'
4
4
 
5
5
  class GlobalMouse < MouseClass
6
+ def initialize
7
+ @_x = ::FFI::MemoryPointer.new(:int)
8
+ @_y = ::FFI::MemoryPointer.new(:int)
9
+ super
10
+ end
11
+
6
12
  def position=(x_y)
7
- err = ::SDL2.SDL_WarpMouseGlobal(*x_y)
13
+ err = ::SDL.WarpMouseGlobal(*x_y)
8
14
  raise RbSDL2Error if err < 0
9
- update
15
+ super
10
16
  end
11
17
 
12
18
  def update
13
- self.button = ::SDL2.SDL_GetGlobalMouseState(x_ptr, y_ptr)
19
+ self.button, self.x, self.y =
20
+ ::SDL.GetGlobalMouseState(@_x, @_y), @_x.read_int, @_y.read_int
14
21
  self
15
22
  end
16
23
  end
@@ -0,0 +1,64 @@
1
+ module RbSDL2
2
+ module Mouse
3
+ class << self
4
+ def capture=(bool)
5
+ err = ::SDL.CaptureMouse(bool ? ::SDL::TRUE : ::SDL::FALSE)
6
+ raise RbSDL2Error if err < 0
7
+ end
8
+
9
+ def relative=(bool)
10
+ err = ::SDL.SetRelativeMouseMode(bool ? ::SDL::TRUE : ::SDL::FALSE)
11
+ raise RbSDL2Error if err < 0
12
+ end
13
+
14
+ def relative? = ::SDL.GetRelativeMouseMode == ::SDL::TRUE
15
+ end
16
+
17
+ require_relative 'global_mouse'
18
+ require_relative 'mouse_wheel'
19
+ require_relative 'relative_mouse'
20
+
21
+ @x, @y = ::FFI::MemoryPointer.new(:int), ::FFI::MemoryPointer.new(:int)
22
+
23
+ class << self
24
+ def global_mouse = GlobalMouse.new.update
25
+
26
+ def relative_mouse = RelativeMouse.instance
27
+
28
+ def button = ::SDL.GetMouseState(nil, nil)
29
+
30
+ require_relative 'mouse_button'
31
+ include MouseButton
32
+
33
+ def position
34
+ ::SDL.GetMouseState(@x, @y)
35
+ [@x.read_int, @y.read_int]
36
+ end
37
+
38
+ def position=(x_y)
39
+ ::SDL.WarpMouseInWindow(nil, *x_y)
40
+ end
41
+
42
+ def x
43
+ ::SDL.GetMouseState(@x, nil)
44
+ @x.read_int
45
+ end
46
+
47
+ def y
48
+ ::SDL.GetMouseState(nil, @y)
49
+ @y.read_int
50
+ end
51
+
52
+ def wheel=(bool)
53
+ if bool
54
+ @wheel ||= MouseWheel.new.tap { |obj| obj.wheel = true }
55
+ else
56
+ @wheel.wheel = false
57
+ @wheel = nil
58
+ end
59
+ end
60
+
61
+ def wheel = @wheel&.update.wheel_y
62
+ end
63
+ end
64
+ end
@@ -1,24 +1,26 @@
1
1
  module RbSDL2
2
2
  module Mouse
3
3
  module MouseButton
4
- SDL_BUTTON = -> (x) { 1 << x - 1 }
5
- SDL_BUTTON_LMASK = SDL_BUTTON.(::SDL2::SDL_BUTTON_LEFT)
6
- SDL_BUTTON_MMASK = SDL_BUTTON.(::SDL2::SDL_BUTTON_MIDDLE)
7
- SDL_BUTTON_RMASK = SDL_BUTTON.(::SDL2::SDL_BUTTON_RIGHT)
8
- SDL_BUTTON_X1MASK = SDL_BUTTON.(::SDL2::SDL_BUTTON_X1)
9
- SDL_BUTTON_X2MASK = SDL_BUTTON.(::SDL2::SDL_BUTTON_X2)
4
+ BUTTON = -> (x) { 1 << x - 1 }
5
+ BUTTON_LMASK = BUTTON.(::SDL::BUTTON_LEFT)
6
+ BUTTON_MMASK = BUTTON.(::SDL::BUTTON_MIDDLE)
7
+ BUTTON_RMASK = BUTTON.(::SDL::BUTTON_RIGHT)
8
+ BUTTON_X1MASK = BUTTON.(::SDL::BUTTON_X1)
9
+ BUTTON_X2MASK = BUTTON.(::SDL::BUTTON_X2)
10
+
11
+ def button?(mask) = mask & button != 0
10
12
 
11
13
  def any_button? = button != 0
12
14
 
13
- def left_button? = SDL_BUTTON_LMASK & button != 0
15
+ def left_button? = button?(BUTTON_LMASK)
14
16
 
15
- def middle_button? = SDL_BUTTON_MMASK & button != 0
17
+ def middle_button? = button?(BUTTON_MMASK)
16
18
 
17
- def right_button? = SDL_BUTTON_RMASK & button != 0
19
+ def right_button? = button?(BUTTON_RMASK)
18
20
 
19
- def x1_button? = SDL_BUTTON_X1MASK & button != 0
21
+ def x1_button? = button?(BUTTON_X1MASK)
20
22
 
21
- def x2_button? = SDL_BUTTON_X2MASK & button != 0
23
+ def x2_button? = button?(BUTTON_X2MASK)
22
24
  end
23
25
  end
24
26
  end
@@ -1,33 +1,25 @@
1
1
  module RbSDL2
2
2
  module Mouse
3
3
  class MouseClass
4
- require 'singleton'
5
- include Singleton
6
-
7
- def initialize
8
- @button = 0
9
- @x_ptr, @y_ptr = Array.new(2) { ::FFI::MemoryPointer.new(:int) }
4
+ def initialize(*)
5
+ @button = @x = @y = 0
6
+ update
10
7
  end
11
8
 
12
- attr_reader :button
13
- private attr_writer :button
9
+ attr_accessor :button, :x, :y
14
10
 
15
11
  require_relative 'mouse_button'
16
12
  include MouseButton
17
13
 
18
14
  def position = [x, y]
19
15
 
16
+ def position=(x_y)
17
+ self.x, self.y = x_y
18
+ end
19
+
20
20
  # 継承先のクラスではこのメソッドをオーバーライドすること。
21
21
  # 戻り値は self が戻ることが期待されている。
22
- def update = self
23
-
24
- private attr_reader :x_ptr
25
-
26
- def x = x_ptr.read_int
27
-
28
- private attr_reader :y_ptr
29
-
30
- def y = y_ptr.read_int
22
+ def update = raise NotImplementedError
31
23
  end
32
24
  end
33
25
  end