reflexion 0.5.3 → 0.7.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 (309) hide show
  1. checksums.yaml +4 -4
  2. data/.doc/ext/reflex/application.cpp +56 -7
  3. data/.doc/ext/reflex/capture_event.cpp +1 -1
  4. data/.doc/ext/reflex/chase_constraint.cpp +84 -0
  5. data/.doc/ext/reflex/clipboard.cpp +65 -0
  6. data/.doc/ext/reflex/color_event.cpp +76 -0
  7. data/.doc/ext/reflex/color_picker.cpp +113 -0
  8. data/.doc/ext/reflex/constraint.cpp +135 -0
  9. data/.doc/ext/reflex/contact_event.cpp +1 -1
  10. data/.doc/ext/reflex/control_change_event.cpp +1 -1
  11. data/.doc/ext/reflex/device.cpp +1 -1
  12. data/.doc/ext/reflex/device_event.cpp +1 -1
  13. data/.doc/ext/reflex/draw_event.cpp +1 -1
  14. data/.doc/ext/reflex/ellipse_shape.cpp +1 -1
  15. data/.doc/ext/reflex/event.cpp +1 -1
  16. data/.doc/ext/reflex/file_dialog.cpp +181 -0
  17. data/.doc/ext/reflex/file_event.cpp +103 -0
  18. data/.doc/ext/reflex/filter.cpp +1 -1
  19. data/.doc/ext/reflex/focus_event.cpp +1 -1
  20. data/.doc/ext/reflex/frame_event.cpp +1 -1
  21. data/.doc/ext/reflex/gamepad.cpp +48 -0
  22. data/.doc/ext/reflex/image_view.cpp +1 -1
  23. data/.doc/ext/reflex/key_event.cpp +1 -274
  24. data/.doc/ext/reflex/line_shape.cpp +1 -1
  25. data/.doc/ext/reflex/link_constraint.cpp +178 -0
  26. data/.doc/ext/reflex/menu.cpp +303 -0
  27. data/.doc/ext/reflex/midi.cpp +9 -2
  28. data/.doc/ext/reflex/midi_event.cpp +1 -1
  29. data/.doc/ext/reflex/motion_event.cpp +1 -1
  30. data/.doc/ext/reflex/native.cpp +40 -10
  31. data/.doc/ext/reflex/note_event.cpp +1 -1
  32. data/.doc/ext/reflex/pin.cpp +156 -0
  33. data/.doc/ext/reflex/pointer.cpp +3 -1
  34. data/.doc/ext/reflex/pointer_event.cpp +3 -3
  35. data/.doc/ext/reflex/polygon_shape.cpp +1 -1
  36. data/.doc/ext/reflex/rect_shape.cpp +1 -1
  37. data/.doc/ext/reflex/reflex.cpp +606 -237
  38. data/.doc/ext/reflex/screen.cpp +27 -1
  39. data/.doc/ext/reflex/scroll_event.cpp +1 -1
  40. data/.doc/ext/reflex/selector.cpp +5 -5
  41. data/.doc/ext/reflex/shape.cpp +1 -1
  42. data/.doc/ext/reflex/snap_constraint.cpp +125 -0
  43. data/.doc/ext/reflex/style.cpp +1 -1
  44. data/.doc/ext/reflex/style_length.cpp +4 -3
  45. data/.doc/ext/reflex/text_event.cpp +104 -0
  46. data/.doc/ext/reflex/timer.cpp +1 -1
  47. data/.doc/ext/reflex/timer_event.cpp +1 -1
  48. data/.doc/ext/reflex/update_event.cpp +1 -1
  49. data/.doc/ext/reflex/view.cpp +206 -79
  50. data/.doc/ext/reflex/wheel_constraint.cpp +142 -0
  51. data/.doc/ext/reflex/wheel_event.cpp +1 -1
  52. data/.doc/ext/reflex/window.cpp +282 -31
  53. data/.github/workflows/release-gem.yml +2 -40
  54. data/.github/workflows/tag.yml +5 -28
  55. data/.github/workflows/test.yml +1 -28
  56. data/ChangeLog.md +79 -0
  57. data/Gemfile.lock +13 -8
  58. data/README.md +1 -0
  59. data/Rakefile +13 -2
  60. data/Reflex.podspec +2 -2
  61. data/VERSION +1 -1
  62. data/ext/reflex/application.cpp +62 -7
  63. data/ext/reflex/capture_event.cpp +1 -1
  64. data/ext/reflex/chase_constraint.cpp +89 -0
  65. data/ext/reflex/clipboard.cpp +69 -0
  66. data/ext/reflex/color_event.cpp +80 -0
  67. data/ext/reflex/color_picker.cpp +121 -0
  68. data/ext/reflex/constraint.cpp +146 -0
  69. data/ext/reflex/contact_event.cpp +1 -1
  70. data/ext/reflex/control_change_event.cpp +1 -1
  71. data/ext/reflex/device.cpp +1 -1
  72. data/ext/reflex/device_event.cpp +1 -1
  73. data/ext/reflex/draw_event.cpp +1 -1
  74. data/ext/reflex/ellipse_shape.cpp +1 -1
  75. data/ext/reflex/event.cpp +1 -1
  76. data/ext/reflex/extconf.rb +4 -2
  77. data/ext/reflex/file_dialog.cpp +194 -0
  78. data/ext/reflex/file_event.cpp +108 -0
  79. data/ext/reflex/filter.cpp +1 -1
  80. data/ext/reflex/focus_event.cpp +1 -1
  81. data/ext/reflex/frame_event.cpp +1 -1
  82. data/ext/reflex/gamepad.cpp +50 -0
  83. data/ext/reflex/image_view.cpp +1 -1
  84. data/ext/reflex/key_event.cpp +1 -275
  85. data/ext/reflex/line_shape.cpp +1 -1
  86. data/ext/reflex/link_constraint.cpp +194 -0
  87. data/ext/reflex/menu.cpp +331 -0
  88. data/ext/reflex/midi.cpp +11 -3
  89. data/ext/reflex/midi_event.cpp +1 -1
  90. data/ext/reflex/motion_event.cpp +1 -1
  91. data/ext/reflex/native.cpp +40 -10
  92. data/ext/reflex/note_event.cpp +1 -1
  93. data/ext/reflex/pin.cpp +165 -0
  94. data/ext/reflex/pointer.cpp +3 -1
  95. data/ext/reflex/pointer_event.cpp +3 -3
  96. data/ext/reflex/polygon_shape.cpp +1 -1
  97. data/ext/reflex/rect_shape.cpp +1 -1
  98. data/ext/reflex/reflex.cpp +608 -237
  99. data/ext/reflex/screen.cpp +31 -2
  100. data/ext/reflex/scroll_event.cpp +1 -1
  101. data/ext/reflex/selector.cpp +5 -5
  102. data/ext/reflex/selector.h +10 -10
  103. data/ext/reflex/shape.cpp +1 -1
  104. data/ext/reflex/snap_constraint.cpp +135 -0
  105. data/ext/reflex/style.cpp +1 -1
  106. data/ext/reflex/style_length.cpp +4 -3
  107. data/ext/reflex/text_event.cpp +111 -0
  108. data/ext/reflex/timer.cpp +1 -1
  109. data/ext/reflex/timer_event.cpp +1 -1
  110. data/ext/reflex/update_event.cpp +1 -1
  111. data/ext/reflex/view.cpp +236 -96
  112. data/ext/reflex/wheel_constraint.cpp +154 -0
  113. data/ext/reflex/wheel_event.cpp +1 -1
  114. data/ext/reflex/window.cpp +318 -40
  115. data/include/reflex/application.h +19 -0
  116. data/include/reflex/clipboard.h +53 -0
  117. data/include/reflex/color_picker.h +65 -0
  118. data/include/reflex/constraint.h +275 -0
  119. data/include/reflex/defs.h +204 -195
  120. data/include/reflex/event.h +180 -88
  121. data/include/reflex/file_dialog.h +73 -0
  122. data/include/reflex/gamepad.h +3 -0
  123. data/include/reflex/menu.h +120 -0
  124. data/include/reflex/midi.h +3 -0
  125. data/include/reflex/pin.h +68 -0
  126. data/include/reflex/pointer.h +4 -0
  127. data/include/reflex/reflex.h +2 -0
  128. data/include/reflex/ruby/application.h +6 -1
  129. data/include/reflex/ruby/clipboard.h +23 -0
  130. data/include/reflex/ruby/color_picker.h +89 -0
  131. data/include/reflex/ruby/constraint.h +94 -0
  132. data/include/reflex/ruby/event.h +62 -29
  133. data/include/reflex/ruby/file_dialog.h +89 -0
  134. data/include/reflex/ruby/gamepad.h +46 -0
  135. data/include/reflex/ruby/menu.h +103 -0
  136. data/include/reflex/ruby/pin.h +40 -0
  137. data/include/reflex/ruby/reflex.h +3 -0
  138. data/include/reflex/ruby/view.h +123 -39
  139. data/include/reflex/ruby/window.h +96 -19
  140. data/include/reflex/ruby.h +3 -0
  141. data/include/reflex/screen.h +11 -2
  142. data/include/reflex/view.h +66 -27
  143. data/include/reflex/window.h +57 -12
  144. data/include/reflex.h +8 -0
  145. data/lib/reflex/application.rb +5 -5
  146. data/lib/reflex/autoinit.rb +3 -1
  147. data/lib/reflex/button.rb +3 -3
  148. data/lib/reflex/chase_constraint.rb +15 -0
  149. data/lib/reflex/clipboard.rb +19 -0
  150. data/lib/reflex/color_event.rb +16 -0
  151. data/lib/reflex/color_picker.rb +45 -0
  152. data/lib/reflex/constraint.rb +29 -0
  153. data/lib/reflex/control_change_event.rb +17 -0
  154. data/lib/reflex/extension.rb +1 -1
  155. data/lib/reflex/file_dialog.rb +70 -0
  156. data/lib/reflex/file_event.rb +37 -0
  157. data/lib/reflex/helper.rb +79 -0
  158. data/lib/reflex/key_event.rb +14 -14
  159. data/lib/reflex/link_constraint.rb +31 -0
  160. data/lib/reflex/menu.rb +92 -0
  161. data/lib/reflex/model.rb +19 -19
  162. data/lib/reflex/note_event.rb +1 -1
  163. data/lib/reflex/pin.rb +39 -0
  164. data/lib/reflex/pointer.rb +30 -1
  165. data/lib/reflex/pointer_event.rb +13 -2
  166. data/lib/reflex/reflex.rb +5 -0
  167. data/lib/reflex/shape.rb +14 -14
  168. data/lib/reflex/snap_constraint.rb +28 -0
  169. data/lib/reflex/style.rb +16 -16
  170. data/lib/reflex/text_event.rb +40 -0
  171. data/lib/reflex/timer.rb +3 -3
  172. data/lib/reflex/view.rb +85 -18
  173. data/lib/reflex/wheel_constraint.rb +28 -0
  174. data/lib/reflex/wheel_event.rb +19 -1
  175. data/lib/reflex/window.rb +25 -13
  176. data/lib/reflex.rb +23 -8
  177. data/pod.rake +1 -1
  178. data/reflex.gemspec +4 -4
  179. data/samples/constraint.rb +152 -0
  180. data/samples/ime.rb +100 -0
  181. data/samples/ios/hello/hello.xcodeproj/project.pbxproj +236 -224
  182. data/samples/menu.rb +32 -0
  183. data/samples/model.rb +3 -3
  184. data/samples/test/alert.rb +93 -0
  185. data/samples/test/always_on.rb +76 -0
  186. data/samples/test/app_background.rb +51 -0
  187. data/samples/test/boundary.rb +75 -0
  188. data/samples/test/callback_exception.rb +101 -0
  189. data/samples/test/cancel.rb +53 -0
  190. data/samples/test/color_picker.rb +63 -0
  191. data/samples/test/file_dialog.rb +102 -0
  192. data/samples/window_style.rb +156 -0
  193. data/src/application.cpp +180 -20
  194. data/src/application.h +95 -5
  195. data/src/clipboard.cpp +81 -0
  196. data/src/color_picker.cpp +113 -0
  197. data/src/color_picker.h +36 -0
  198. data/src/constraint.cpp +1662 -0
  199. data/src/constraint.h +64 -0
  200. data/src/event.cpp +416 -252
  201. data/src/event.h +13 -2
  202. data/src/file_dialog.cpp +163 -0
  203. data/src/file_dialog.h +52 -0
  204. data/src/gamepad.cpp +42 -5
  205. data/src/gamepad.h +4 -0
  206. data/src/ios/app_delegate.mm +5 -3
  207. data/src/ios/application.mm +29 -0
  208. data/src/ios/clipboard.mm +44 -0
  209. data/src/ios/color_picker.mm +19 -0
  210. data/src/ios/event.h +6 -2
  211. data/src/ios/event.mm +31 -12
  212. data/src/ios/file_dialog.mm +21 -0
  213. data/src/ios/gamepad.mm +4 -4
  214. data/src/ios/menu.mm +41 -0
  215. data/src/ios/reflex.mm +8 -0
  216. data/src/ios/screen.mm +26 -0
  217. data/src/ios/view_controller.mm +47 -42
  218. data/src/ios/window.mm +44 -9
  219. data/src/menu.cpp +387 -0
  220. data/src/menu.h +81 -0
  221. data/src/midi.cpp +61 -31
  222. data/src/osx/app_delegate.h +4 -0
  223. data/src/osx/app_delegate.mm +168 -139
  224. data/src/osx/application.mm +103 -5
  225. data/src/osx/clipboard.mm +45 -0
  226. data/src/osx/color_picker.mm +112 -0
  227. data/src/osx/event.h +10 -0
  228. data/src/osx/event.mm +114 -30
  229. data/src/osx/file_dialog.mm +168 -0
  230. data/src/osx/gamepad.mm +2 -2
  231. data/src/osx/gamepad_hid.mm +1 -1
  232. data/src/osx/menu.h +25 -0
  233. data/src/osx/menu.mm +516 -0
  234. data/src/osx/native_window.h +16 -2
  235. data/src/osx/native_window.mm +141 -57
  236. data/src/osx/opengl_view.h +2 -1
  237. data/src/osx/opengl_view.mm +229 -37
  238. data/src/osx/reflex.mm +38 -0
  239. data/src/osx/screen.mm +36 -0
  240. data/src/osx/window.mm +117 -24
  241. data/src/pin.cpp +137 -0
  242. data/src/pointer.cpp +36 -16
  243. data/src/pointer.h +10 -0
  244. data/src/rays.h +46 -0
  245. data/src/sdl/application.cpp +73 -8
  246. data/src/sdl/clipboard.cpp +39 -0
  247. data/src/sdl/color_picker.cpp +18 -0
  248. data/src/sdl/event.cpp +44 -6
  249. data/src/sdl/event.h +18 -3
  250. data/src/sdl/file_dialog.cpp +20 -0
  251. data/src/sdl/gamepad.cpp +3 -7
  252. data/src/sdl/menu.cpp +40 -0
  253. data/src/sdl/reflex.cpp +20 -0
  254. data/src/sdl/screen.cpp +36 -0
  255. data/src/sdl/window.cpp +168 -37
  256. data/src/shape.cpp +15 -10
  257. data/src/view.cpp +583 -233
  258. data/src/view.h +22 -4
  259. data/src/vk.h +416 -0
  260. data/src/win32/application.cpp +167 -12
  261. data/src/win32/application.h +20 -0
  262. data/src/win32/clipboard.cpp +210 -0
  263. data/src/win32/color_picker.cpp +82 -0
  264. data/src/win32/event.cpp +123 -11
  265. data/src/win32/event.h +22 -3
  266. data/src/win32/file_dialog.cpp +226 -0
  267. data/src/win32/gamepad.cpp +9 -2
  268. data/src/win32/menu.cpp +490 -0
  269. data/src/win32/menu.h +35 -0
  270. data/src/win32/opengl.cpp +2 -9
  271. data/src/win32/reflex.cpp +44 -3
  272. data/src/win32/screen.cpp +164 -3
  273. data/src/win32/screen.h +8 -0
  274. data/src/win32/tray.cpp +191 -0
  275. data/src/win32/tray.h +22 -0
  276. data/src/win32/vk.cpp +11 -0
  277. data/src/win32/window.cpp +858 -135
  278. data/src/win32/window.h +9 -0
  279. data/src/window.cpp +929 -183
  280. data/src/window.h +77 -33
  281. data/src/world.cpp +86 -15
  282. data/src/world.h +9 -2
  283. data/test/helper.rb +24 -0
  284. data/test/test_application.rb +101 -1
  285. data/test/test_chase_constraint.rb +122 -0
  286. data/test/test_clipboard.rb +54 -0
  287. data/test/test_color_event.rb +36 -0
  288. data/test/test_color_picker.rb +62 -0
  289. data/test/test_constraint.rb +184 -0
  290. data/test/test_event.rb +1 -1
  291. data/test/test_file_dialog.rb +48 -0
  292. data/test/test_file_event.rb +43 -0
  293. data/test/test_has_text_preedit.rb +54 -0
  294. data/test/test_key_event.rb +23 -2
  295. data/test/test_link_constraint.rb +237 -0
  296. data/test/test_menu.rb +237 -0
  297. data/test/test_pin.rb +65 -0
  298. data/test/test_pointer.rb +50 -26
  299. data/test/test_pointer_event.rb +25 -10
  300. data/test/test_reflex.rb +36 -0
  301. data/test/test_screen.rb +24 -2
  302. data/test/test_snap_constraint.rb +140 -0
  303. data/test/test_text_event.rb +54 -0
  304. data/test/test_view.rb +152 -25
  305. data/test/test_wheel_constraint.rb +125 -0
  306. data/test/test_wheel_event.rb +24 -10
  307. data/test/test_window.rb +205 -43
  308. metadata +154 -10
  309. data/.github/workflows/utils.rb +0 -127
@@ -0,0 +1,237 @@
1
+ require_relative 'helper'
2
+
3
+
4
+ class TestLinkConstraint < Test::Unit::TestCase
5
+
6
+ include HasWindow
7
+
8
+ def view(x = 0, y = 0, w = 50, h = 50, **options, &block)
9
+ Reflex::View.new(
10
+ frame: [x, y, w, h],
11
+ shape: Reflex::RectShape.new(density: 1),
12
+ **options, &block)
13
+ end
14
+
15
+ def point(...)
16
+ Reflex::Point.new(...)
17
+ end
18
+
19
+ def setup_views(win = window)
20
+ v1 = view 100, 100, dynamic: true
21
+ v2 = view 200, 100, static: true
22
+ win&.add v1
23
+ win&.add v2
24
+ [v1, v2, win, win&.root]
25
+ end
26
+
27
+ def test_initial_state()
28
+ v1, v2, = setup_views
29
+
30
+ assert_equal v1, v1.link(v2) .pins[0].view
31
+ assert_equal v2, v1.link(v2) .pins[1].view
32
+ assert_nil v1.link(v2) .axis
33
+ assert_equal_point point(1, 0), v1.link(v2, axis: [1, 0]).axis
34
+ assert_equal 100, v1.link(v2) .distance
35
+ assert_equal 1, v1.link(v2, distance: 1) .distance
36
+ assert_equal 2, v1.link(v2, dist: 2) .distance
37
+ assert_nil v1.link(v2) .range
38
+ assert_equal 3..3, v1.link(v2, range: 3) .range
39
+ assert_equal 4..5, v1.link(v2, range: 4..5) .range
40
+ assert_nil v1.link(v2) .motor
41
+ assert_equal 6, v1.link(v2, motor: 6) .motor
42
+ assert_nil v1.link(v2) .force
43
+ assert_equal 8, v1.link(v2, force: 8) .force
44
+ assert_nil v1.link(v2) .spring
45
+ assert_equal 7, v1.link(v2, spring: 7) .spring
46
+ assert_in_delta 0.7, v1.link(v2) .damping
47
+ assert_in_delta 0.1, v1.link(v2, damping: 0.1).damping
48
+ assert_false v1.link(v2) .collide?
49
+ assert_true v1.link(v2) .active?
50
+ assert_false v1.link(v2) .removed?
51
+ end
52
+
53
+ def test_link_to_view()
54
+ v1, v2, _, root = setup_views
55
+ root.gravity(-900, 0)
56
+
57
+ c = v1.link v2, dist: 50
58
+ assert_equal v2, c.pins[1].view
59
+
60
+ 60.times {root.update_world}
61
+ assert_equal_point point(150, 100), v1.pos
62
+ assert_in_delta 50, c.current_distance, 0.01
63
+ end
64
+
65
+ def test_link_to_world()
66
+ v1, _, _, root = setup_views
67
+ root.gravity(-900, 0)
68
+
69
+ c = v1.pin.link [200, 125], dist: 50
70
+ assert_nil c.pins[1].view
71
+
72
+ 60.times {root.update_world}
73
+ assert_equal_point point(125, 100), v1.pos
74
+ assert_in_delta 50, c.current_distance, 0.01
75
+ end
76
+
77
+ def test_distance()
78
+ v1, v2, = setup_views
79
+
80
+ c = v1.link v2, dist: 80, spring: 4
81
+ assert_equal 80, c.distance
82
+ assert_equal 80, c.dist
83
+
84
+ c.dist = 90
85
+ assert_equal 90, c.distance
86
+ end
87
+
88
+ def test_range()
89
+ v1, v2, _, root = setup_views
90
+ root.gravity 0, 900
91
+
92
+ c = v1.link v2, distance: 100, range: 0..120, spring: 1, damping: 0
93
+ 60.times {root.update_world}
94
+ assert_operator c.current_distance, :<=, 121
95
+
96
+ c.range = nil
97
+ assert_nil c.range
98
+
99
+ assert_raise(ArgumentError) {c.range = 'invalid'}
100
+ end
101
+
102
+ def test_motor()
103
+ v1, v2, = setup_views
104
+
105
+ c = v1.link v2, motor: 10
106
+ assert_equal 10, c.motor
107
+
108
+ c.motor = nil
109
+ assert_nil c.motor
110
+ end
111
+
112
+ def test_force()
113
+ v1, v2, = setup_views
114
+
115
+ c = v1.link v2, motor: 10, force: 500
116
+ assert_equal 500, c.force
117
+
118
+ c.force = nil
119
+ assert_nil c.force
120
+
121
+ c.force = 100
122
+ assert_equal 100, c.force
123
+
124
+ assert_raise(ArgumentError) {c.force = -1}
125
+ end
126
+
127
+ def test_axis_to_view()
128
+ v1, v2, _, root = setup_views
129
+ root.gravity 900, 900
130
+
131
+ c = v1.link v2, axis: [1, 0]
132
+ assert_equal_point point(1, 0), c.axis
133
+ assert_equal v2, c.pins[1].view
134
+
135
+ root.update_world
136
+ assert_operator v1.linear_velocity.x, :>, 0
137
+ assert_in_delta 0, v1.linear_velocity.y # locked to the axis
138
+ end
139
+
140
+ def test_axis_to_world()
141
+ v1, _, _, root = setup_views
142
+ root.gravity 900, 900
143
+
144
+ c = v1.pin.link axis: [1, 0]
145
+ assert_nil c.pins[1].view
146
+
147
+ root.update_world
148
+ assert_operator v1.linear_velocity.x, :>, 0
149
+ assert_in_delta 0, v1.linear_velocity.y
150
+ end
151
+
152
+ def test_axis_locks_rotation()
153
+ v1, v2, _, root = setup_views
154
+
155
+ v1.link v2, axis: [1, 0]
156
+
157
+ v1.angular_velocity = 90
158
+ 3.times {root.update_world}
159
+ assert_in_delta 0, v1.angular_velocity # prismatic locks relative rotation
160
+ end
161
+
162
+ def test_axis_change()
163
+ v1, v2, _, root = setup_views
164
+ root.gravity 900, 900
165
+
166
+ c = v1.link v2, axis: [1, 0]
167
+ root.update_world
168
+ assert_operator v1.linear_velocity.x, :>, 0
169
+ assert_in_delta 0, v1.linear_velocity.y
170
+
171
+ c.axis = [0, 1]
172
+ assert_equal_point point(0, 1), c.axis
173
+
174
+ root.update_world
175
+ assert_operator v1.linear_velocity.y, :>, 0
176
+ end
177
+
178
+ def test_axis_morphs_between_distance_and_rail()
179
+ v1, v2, = setup_views
180
+
181
+ c = v1.link v2
182
+ assert_nil c.axis # a distance joint has no axis
183
+
184
+ c.axis = [1, 0]
185
+ assert_equal_point point(1, 0), c.axis # now a rail
186
+
187
+ c.axis = nil
188
+ assert_nil c.axis # back to a distance joint
189
+ end
190
+
191
+ def test_axis_distance()
192
+ v1, v2, _, root = setup_views
193
+
194
+ c = v1.link v2, axis: [1, 0], distance: 30, spring: 4, damping: 1
195
+ assert_equal 30, c.distance
196
+
197
+ 60.times {root.update_world}
198
+ assert_in_delta 30, c.current_distance, 1 # the spring drives to the rest
199
+ end
200
+
201
+ def test_axis_distance_is_rest_not_translation()
202
+ v1, v2, _, root = setup_views
203
+ root.gravity 900, 0
204
+
205
+ c = v1.link v2, axis: [1, 0]
206
+ 3.times {root.update_world}
207
+ assert_operator c.current_distance.abs, :>, 0 # slides along the axis
208
+ assert_in_delta 0, c.distance # but the rest stays put
209
+ end
210
+
211
+ def test_axis_range()
212
+ v1, v2, _, root = setup_views
213
+ root.gravity 0, 900
214
+
215
+ c = v1.pin(25, 25).link v2.pin(25, 25), axis: [0, 1], range: 100..200
216
+ assert_equal 100..200, c.range
217
+
218
+ 60.times {root.update_world}
219
+ assert_equal_point point(200, 300), v1.pos
220
+ end
221
+
222
+ def test_axis_motor()
223
+ v1, v2, _, root = setup_views
224
+ root.gravity(-900, 0)
225
+
226
+ c = v1.link v2, axis: [1, 0], motor: 100
227
+ assert_equal 100, c.motor
228
+
229
+ 3.times {root.update_world}
230
+ assert_operator v1.linear_velocity.x, :>, 1
231
+ assert_in_delta 0, v1.linear_velocity.y
232
+
233
+ c.motor = nil
234
+ assert_nil c.motor
235
+ end
236
+
237
+ end# TestLinkConstraint
data/test/test_menu.rb ADDED
@@ -0,0 +1,237 @@
1
+ require_relative 'helper'
2
+
3
+
4
+ class TestMenu < Test::Unit::TestCase
5
+
6
+ def menu(*args, &block)
7
+ Reflex::Menu.new(*args, &block)
8
+ end
9
+
10
+ def test_initialize()
11
+ assert_equal '', menu.label
12
+ assert_equal 'File', menu(:File).label
13
+ end
14
+
15
+ def test_add_child()
16
+ menu.tap do |m|
17
+ m.add menu(:A)
18
+ m.add menu(:B)
19
+ m.add menu(:C), index: 1
20
+ assert_equal 3, m.size
21
+ assert_equal %w[A C B], m.map(&:label)
22
+ end
23
+
24
+ menu.tap do |m|
25
+ m.add menu(:A)
26
+ m.add menu(:B), index: 0
27
+ m.add menu(:C), index: m.size
28
+ assert_equal %w[B A C], m.map(&:label)
29
+ end
30
+
31
+ menu.tap do |m|
32
+ m.add menu(:A)
33
+ m.add menu(:B), index: 99
34
+ m.add menu(:C), index: -1
35
+ m.add menu(:D), index: nil
36
+ assert_equal %w[A B C D], m.map(&:label)
37
+ end
38
+ end
39
+
40
+ def test_add_twice_to_same_parent()
41
+ m = menu
42
+ c = m.add menu
43
+ m.add c
44
+ assert_equal 1, m.size
45
+ end
46
+
47
+ def test_add_child_having_other_parent_raises()
48
+ a, b = menu, menu
49
+ c = a.add menu
50
+ assert_raise(ArgumentError, Reflex::ReflexError) {b.add c}
51
+ end
52
+
53
+ def test_add_nil_raises()
54
+ assert_raise(TypeError, ArgumentError) {menu.add nil}
55
+ end
56
+
57
+ def test_remove()
58
+ m = menu
59
+ a = m.add menu(:A)
60
+ m.add menu(:B)
61
+ m.remove a
62
+ assert_equal %w[B], m.map(&:label)
63
+ end
64
+
65
+ def test_clear_children()
66
+ m = menu
67
+ m.add menu(:A)
68
+ m.clear_children
69
+ assert_true m.empty?
70
+ end
71
+
72
+ def test_find_children()
73
+ root = menu
74
+ root.add(menu(:A)).name = :x
75
+ root.add(menu(:B)).name = :x
76
+ root.add(menu(:C)).name = :y
77
+ assert_equal 2, root.find_children(:x).size
78
+ end
79
+
80
+ def test_find_children_recursive()
81
+ root = menu
82
+ file = root.add menu(:File)
83
+ file.add(menu :Open).name = :x
84
+ assert_equal 1, root.find_children(:x) .size
85
+ assert_equal 0, root.find_children(:x, false).size
86
+ end
87
+
88
+ def test_label()
89
+ m = menu
90
+ m.label = :Open
91
+ assert_equal 'Open', m.label
92
+ end
93
+
94
+ def test_label_changes_separator()
95
+ m = menu :File
96
+ assert_false m.separator?
97
+ m.label = '-'
98
+ assert_true m.separator?
99
+ m.label = :Edit
100
+ assert_false m.separator?
101
+ end
102
+
103
+ def test_enable_and_disable()
104
+ m = menu
105
+ assert_true m.enabled?
106
+ m.enable false
107
+ assert_false m.enabled?
108
+ m.enable
109
+ assert_true m.enabled?
110
+ m.disable
111
+ assert_false m.enabled?
112
+ end
113
+
114
+ def test_check_and_uncheck()
115
+ m = menu
116
+ assert_false m.checked?
117
+ m.check true
118
+ assert_true m.checked?
119
+ m.uncheck
120
+ assert_false m.checked?
121
+ m.check
122
+ assert_true m.checked?
123
+ end
124
+
125
+ def test_shortcut()
126
+ m = menu
127
+ m.shortcut_key = :s
128
+ assert_equal :s, m.shortcut_key
129
+ assert_equal [], m.shortcut_modifiers
130
+
131
+ m.shortcut = [:c, :control]
132
+ assert_equal :c, m.shortcut_key
133
+ assert_equal [:control], m.shortcut_modifiers
134
+ end
135
+
136
+ def test_shortcut_key_symbol_roundtrip()
137
+ m = menu
138
+ # non-character keys are representable now (were impossible as strings)
139
+ m.shortcut_key = :f1
140
+ assert_equal :f1, m.shortcut_key
141
+ m.shortcut_key = :left
142
+ assert_equal :left, m.shortcut_key
143
+
144
+ # a KeyCode constant is also accepted directly
145
+ m.shortcut_key = Reflex::KEY_A
146
+ assert_equal :a, m.shortcut_key
147
+
148
+ # nil clears it
149
+ m.shortcut_key = nil
150
+ assert_nil m.shortcut_key
151
+ end
152
+
153
+ def test_shortcut_key_unknown_symbol_raises()
154
+ assert_raise(ArgumentError) {menu.shortcut_key = :nonexistent}
155
+ end
156
+
157
+ def test_shortcut_key_keeps_modifiers()
158
+ m = menu
159
+ m.shortcut = [:c, :control, :shift]
160
+ assert_equal :c, m.shortcut_key
161
+ assert_equal %i[control shift].sort, m.shortcut_modifiers.sort
162
+ m.shortcut_key = :v
163
+ assert_equal :v, m.shortcut_key
164
+ assert_equal %i[control shift].sort, m.shortcut_modifiers.sort
165
+ end
166
+
167
+ def test_shortcut_modifiers_unsupported_on_platform_raise()
168
+ if osx?
169
+ assert_raise(ArgumentError) {menu.shortcut_modifiers = [:win]}
170
+ elsif win32?
171
+ assert_raise(ArgumentError) {menu.shortcut_modifiers = [:command]}
172
+ assert_raise(ArgumentError) {menu.shortcut_modifiers = [:win]}
173
+ end
174
+ end
175
+
176
+ def test_image()
177
+ m, img = menu, Reflex::Image.new(8, 8)
178
+ assert_nil m.image
179
+ m.image = img
180
+ assert_equal img, m.image
181
+ m.image = nil
182
+ assert_nil m.image
183
+
184
+ assert_raise(TypeError) {m.image = 1}
185
+ end
186
+
187
+ def test_separator()
188
+ assert_false menu(:File).separator?
189
+ assert_true menu('-').separator?
190
+ assert_true menu('---').separator?
191
+ assert_false menu('').separator?
192
+ end
193
+
194
+ def test_parent()
195
+ m = menu
196
+ c = m.add menu
197
+ assert_equal m, c.parent
198
+ assert_nil m.parent
199
+ m.remove c
200
+ assert_nil c.parent
201
+ end
202
+
203
+ def test_children()
204
+ m = menu
205
+ c = m.add menu
206
+ assert_equal [c], m.children
207
+ assert_equal c, m.first
208
+ end
209
+
210
+ def test_each_without_block()
211
+ m = menu
212
+ m.add menu(:A)
213
+ assert_kind_of Enumerator, m.each
214
+ assert_equal %w[A], m.each.map(&:label)
215
+ end
216
+
217
+ def test_nested()
218
+ root = menu
219
+ file = root.add menu(:File)
220
+ file.add menu(:Open)
221
+ assert_equal 'Open', root.first.first.label
222
+ end
223
+
224
+ def test_event_hooks()
225
+ m = menu
226
+ fired = []
227
+ %i[click show hide open_submenu close_submenu].each {|ev| m.on(ev) {|e| fired << ev}}
228
+ e = Reflex::UpdateEvent.new 0, 0
229
+ m.on_click e
230
+ m.on_show e
231
+ m.on_hide e
232
+ m.on_open_submenu e
233
+ m.on_close_submenu e
234
+ assert_equal %i[click show hide open_submenu close_submenu], fired
235
+ end
236
+
237
+ end# TestMenu
data/test/test_pin.rb ADDED
@@ -0,0 +1,65 @@
1
+ require_relative 'helper'
2
+
3
+
4
+ class TestPin < Test::Unit::TestCase
5
+
6
+ def pin(...)
7
+ Reflex::Pin.new(...)
8
+ end
9
+
10
+ def view()
11
+ Reflex::View.new frame: [0, 0, 50, 50]
12
+ end
13
+
14
+ def point(*args)
15
+ Reflex::Point.new(*args)
16
+ end
17
+
18
+ def test_initialize()
19
+ v = view
20
+ assert_nil pin .view
21
+ assert_nil pin .pos
22
+ assert_nil pin( 1) .view
23
+ assert_equal point(1, 1), pin( 1) .pos
24
+ assert_nil pin( 2, 3) .view
25
+ assert_equal point(2, 3), pin( 2, 3) .pos
26
+ assert_equal v, pin(v) .view
27
+ assert_nil pin(v) .pos
28
+ assert_equal v, pin(v, 4, 5) .view
29
+ assert_equal point(4, 5), pin(v, 4, 5) .pos
30
+ assert_equal v, pin(v, [6, 7]).view
31
+ assert_equal point(6, 7), pin(v, [6, 7]).pos
32
+ assert_equal v, pin(v, point(8, 9)).view
33
+ assert_equal point(8, 9), pin(v, point(8, 9)).pos
34
+ end
35
+
36
+ def test_dup()
37
+ v = view
38
+ assert_nil pin .dup.view
39
+ assert_nil pin .dup.pos
40
+ assert_nil pin( 1, 2).dup.view
41
+ assert_equal point(1, 2), pin( 1, 2).dup.pos
42
+ assert_equal v, pin(v, 3, 4).dup.view
43
+ assert_equal point(3, 4), pin(v, 3, 4).dup.pos
44
+ end
45
+
46
+ def test_pin()
47
+ v = view
48
+ assert_instance_of Reflex::Pin, v.pin
49
+
50
+ assert_equal v, v.pin .view
51
+ assert_nil v.pin .pos
52
+ assert_equal v, v.pin( 1) .view
53
+ assert_equal point(1, 1), v.pin( 1) .pos
54
+ assert_equal v, v.pin( 2, 3) .view
55
+ assert_equal point(2, 3), v.pin( 2, 3) .pos
56
+ assert_equal v, v.pin( [4, 5]).view
57
+ assert_equal point(4, 5), v.pin( [4, 5]).pos
58
+ assert_equal v, v.pin(point(6, 7)).view
59
+ assert_equal point(6, 7), v.pin(point(6, 7)).pos
60
+
61
+ assert_raise(TypeError) {v.pin view}
62
+ assert_raise(TypeError) {v.pin "invalid"}
63
+ end
64
+
65
+ end# TestPin
data/test/test_pointer.rb CHANGED
@@ -3,20 +3,24 @@ require_relative 'helper'
3
3
 
4
4
  class TestPointer < Test::Unit::TestCase
5
5
 
6
- TYPE_NONE = Reflex::Pointer::TYPE_NONE
7
- MOUSE = Reflex::Pointer::MOUSE
8
- LEFT = Reflex::Pointer::MOUSE_LEFT
9
- RIGHT = Reflex::Pointer::MOUSE_RIGHT
10
- MIDDLE = Reflex::Pointer::MOUSE_MIDDLE
11
- TOUCH = Reflex::Pointer::TOUCH
12
- PEN = Reflex::Pointer::PEN
13
-
14
- ACTION_NONE = Reflex::Pointer::ACTION_NONE
15
- DOWN = Reflex::Pointer::DOWN
16
- UP = Reflex::Pointer::UP
17
- MOVE = Reflex::Pointer::MOVE
18
- STAY = Reflex::Pointer::STAY
19
- CANCEL = Reflex::Pointer::CANCEL
6
+ R = Reflex
7
+
8
+ TYPE_NONE = R::Pointer::TYPE_NONE
9
+ MOUSE = R::Pointer::MOUSE
10
+ LEFT = R::Pointer::MOUSE_LEFT
11
+ RIGHT = R::Pointer::MOUSE_RIGHT
12
+ MIDDLE = R::Pointer::MOUSE_MIDDLE
13
+ TOUCH = R::Pointer::TOUCH
14
+ PEN = R::Pointer::PEN
15
+
16
+ ACTION_NONE = R::Pointer::ACTION_NONE
17
+ DOWN = R::Pointer::DOWN
18
+ UP = R::Pointer::UP
19
+ MOVE = R::Pointer::MOVE
20
+ CANCEL = R::Pointer::CANCEL
21
+ ENTER = R::Pointer::ENTER
22
+ LEAVE = R::Pointer::LEAVE
23
+ STAY = R::Pointer::STAY
20
24
 
21
25
  T = true
22
26
  F = false
@@ -26,8 +30,7 @@ class TestPointer < Test::Unit::TestCase
26
30
  position: 0, modifiers: 0, click_count: 0, drag: false,
27
31
  time: 0)
28
32
 
29
- Reflex::Pointer.new(
30
- id, types, action, position, modifiers, click_count, drag, time)
33
+ R::Pointer.new(id, types, action, position, modifiers, click_count, drag, time)
31
34
  end
32
35
 
33
36
  def test_initialize()
@@ -44,7 +47,7 @@ class TestPointer < Test::Unit::TestCase
44
47
  assert_equal [2, 3], p.position.to_a
45
48
  assert_equal 2, p.x
46
49
  assert_equal 3, p.y
47
- assert_equal 4, p.modifiers
50
+ assert_equal [:shift], p.modifiers
48
51
  assert_equal 5, p.click_count
49
52
  assert_equal true, p.drag?
50
53
  assert_equal 6, p.time
@@ -99,28 +102,34 @@ class TestPointer < Test::Unit::TestCase
99
102
  def action(a)
100
103
  pointer(action: a).tap do |o|
101
104
  def o.test()
102
- [action, down?, up?, move?, cancel?, stay?]
105
+ [action, down?, up?, move?, cancel?, enter?, leave?, stay?]
103
106
  end
104
107
  end
105
108
  end
106
109
 
107
110
  o = action ACTION_NONE
108
- assert_equal [:none, F, F, F, F, F], o.test
111
+ assert_equal [:none, F, F, F, F, F, F, F], o.test
109
112
 
110
113
  o = action DOWN
111
- assert_equal [:down, T, F, F, F, F], o.test
114
+ assert_equal [:down, T, F, F, F, F, F, F], o.test
112
115
 
113
116
  o = action UP
114
- assert_equal [:up, F, T, F, F, F], o.test
117
+ assert_equal [:up, F, T, F, F, F, F, F], o.test
115
118
 
116
119
  o = action MOVE
117
- assert_equal [:move, F, F, T, F, F], o.test
120
+ assert_equal [:move, F, F, T, F, F, F, F], o.test
118
121
 
119
122
  o = action CANCEL
120
- assert_equal [:cancel, F, F, F, T, F], o.test
123
+ assert_equal [:cancel, F, F, F, T, F, F, F], o.test
124
+
125
+ o = action ENTER
126
+ assert_equal [:enter, F, F, F, F, T, F, F], o.test
127
+
128
+ o = action LEAVE
129
+ assert_equal [:leave, F, F, F, F, F, T, F], o.test
121
130
 
122
131
  o = action STAY
123
- assert_equal [:stay, F, F, F, F, T], o.test
132
+ assert_equal [:stay, F, F, F, F, F, F, T], o.test
124
133
  end
125
134
 
126
135
  def test_position()
@@ -133,6 +142,12 @@ class TestPointer < Test::Unit::TestCase
133
142
  assert_equal 2, pointer(position: [1, 2]).y
134
143
  end
135
144
 
145
+ def test_modifiers()
146
+ p = pointer modifiers: R::MOD_SHIFT | R::MOD_NUMPAD
147
+ assert_equal [:shift], p.modifiers
148
+ assert_equal [:shift, :numpad], p.modifiers(all: true)
149
+ end
150
+
136
151
  def test_down()
137
152
  assert_equal 1, pointer(id: 1, action: DOWN).down.id # DOWN pointer's down() returns itself
138
153
  assert_nil pointer(id: 2, action: UP) .down
@@ -142,8 +157,8 @@ class TestPointer < Test::Unit::TestCase
142
157
  assert_equal pointer, pointer
143
158
 
144
159
  assert_not_equal pointer, pointer(id: 1)
145
- assert_not_equal pointer, pointer(types: Reflex::Pointer::PEN)
146
- assert_not_equal pointer, pointer(action: Reflex::Pointer::UP)
160
+ assert_not_equal pointer, pointer(types: R::Pointer::PEN)
161
+ assert_not_equal pointer, pointer(action: R::Pointer::UP)
147
162
  assert_not_equal pointer, pointer(position: 2)
148
163
  assert_not_equal pointer, pointer(modifiers: 3)
149
164
  assert_not_equal pointer, pointer(click_count: 4)
@@ -151,4 +166,13 @@ class TestPointer < Test::Unit::TestCase
151
166
  assert_not_equal pointer, pointer(time: 5)
152
167
  end
153
168
 
169
+ def test_inspect()
170
+ assert_equal(
171
+ '#<Reflex::Pointer id:1 [:mouse, :mouse_left] :up (2.0, 3.0) mod:[:shift, :control] click:5 drag:true time:4.0>',
172
+ pointer(
173
+ id: 1, types: MOUSE | LEFT, action: UP, position: [2, 3], modifiers: 6,
174
+ click_count: 5, drag: true, time: 4
175
+ ).inspect)
176
+ end
177
+
154
178
  end# TestPointer