reflexion 0.5.2 → 0.6.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 (145) hide show
  1. checksums.yaml +4 -4
  2. data/.doc/ext/reflex/application.cpp +19 -1
  3. data/.doc/ext/reflex/chase_constraint.cpp +84 -0
  4. data/.doc/ext/reflex/clipboard.cpp +65 -0
  5. data/.doc/ext/reflex/constraint.cpp +135 -0
  6. data/.doc/ext/reflex/key_event.cpp +6 -6
  7. data/.doc/ext/reflex/link_constraint.cpp +178 -0
  8. data/.doc/ext/reflex/menu.cpp +302 -0
  9. data/.doc/ext/reflex/native.cpp +22 -4
  10. data/.doc/ext/reflex/pin.cpp +156 -0
  11. data/.doc/ext/reflex/pointer.cpp +2 -0
  12. data/.doc/ext/reflex/pointer_event.cpp +1 -1
  13. data/.doc/ext/reflex/reflex.cpp +42 -7
  14. data/.doc/ext/reflex/selector.cpp +4 -4
  15. data/.doc/ext/reflex/snap_constraint.cpp +125 -0
  16. data/.doc/ext/reflex/style_length.cpp +3 -2
  17. data/.doc/ext/reflex/view.cpp +96 -23
  18. data/.doc/ext/reflex/wheel_constraint.cpp +142 -0
  19. data/.doc/ext/reflex/window.cpp +59 -17
  20. data/.github/workflows/release-gem.yml +10 -1
  21. data/.github/workflows/test.yml +9 -0
  22. data/ChangeLog.md +30 -0
  23. data/README.md +1 -0
  24. data/VERSION +1 -1
  25. data/ext/reflex/application.cpp +21 -1
  26. data/ext/reflex/chase_constraint.cpp +89 -0
  27. data/ext/reflex/clipboard.cpp +69 -0
  28. data/ext/reflex/constraint.cpp +146 -0
  29. data/ext/reflex/key_event.cpp +6 -6
  30. data/ext/reflex/link_constraint.cpp +194 -0
  31. data/ext/reflex/menu.cpp +330 -0
  32. data/ext/reflex/native.cpp +22 -4
  33. data/ext/reflex/pin.cpp +165 -0
  34. data/ext/reflex/pointer.cpp +2 -0
  35. data/ext/reflex/pointer_event.cpp +1 -1
  36. data/ext/reflex/reflex.cpp +42 -7
  37. data/ext/reflex/selector.cpp +4 -4
  38. data/ext/reflex/selector.h +1 -1
  39. data/ext/reflex/snap_constraint.cpp +135 -0
  40. data/ext/reflex/style_length.cpp +3 -2
  41. data/ext/reflex/view.cpp +117 -37
  42. data/ext/reflex/wheel_constraint.cpp +154 -0
  43. data/ext/reflex/window.cpp +65 -18
  44. data/include/reflex/application.h +9 -0
  45. data/include/reflex/clipboard.h +53 -0
  46. data/include/reflex/constraint.h +275 -0
  47. data/include/reflex/defs.h +204 -195
  48. data/include/reflex/event.h +2 -0
  49. data/include/reflex/menu.h +120 -0
  50. data/include/reflex/pin.h +68 -0
  51. data/include/reflex/pointer.h +4 -0
  52. data/include/reflex/ruby/clipboard.h +23 -0
  53. data/include/reflex/ruby/constraint.h +94 -0
  54. data/include/reflex/ruby/menu.h +103 -0
  55. data/include/reflex/ruby/pin.h +40 -0
  56. data/include/reflex/ruby/view.h +36 -0
  57. data/include/reflex/ruby/window.h +36 -18
  58. data/include/reflex/view.h +39 -12
  59. data/include/reflex/window.h +17 -4
  60. data/include/reflex.h +5 -0
  61. data/lib/reflex/chase_constraint.rb +15 -0
  62. data/lib/reflex/clipboard.rb +19 -0
  63. data/lib/reflex/constraint.rb +29 -0
  64. data/lib/reflex/extension.rb +1 -1
  65. data/lib/reflex/helper.rb +28 -0
  66. data/lib/reflex/key_event.rb +7 -12
  67. data/lib/reflex/link_constraint.rb +31 -0
  68. data/lib/reflex/menu.rb +76 -0
  69. data/lib/reflex/pin.rb +39 -0
  70. data/lib/reflex/pointer.rb +18 -0
  71. data/lib/reflex/pointer_event.rb +1 -1
  72. data/lib/reflex/snap_constraint.rb +28 -0
  73. data/lib/reflex/view.rb +56 -4
  74. data/lib/reflex/wheel_constraint.rb +28 -0
  75. data/lib/reflex/wheel_event.rb +9 -0
  76. data/lib/reflex.rb +15 -6
  77. data/pod.rake +4 -2
  78. data/reflex.gemspec +3 -3
  79. data/samples/constraint.rb +152 -0
  80. data/samples/menu.rb +29 -0
  81. data/src/application.cpp +21 -2
  82. data/src/application.h +5 -0
  83. data/src/clipboard.cpp +81 -0
  84. data/src/constraint.cpp +1662 -0
  85. data/src/constraint.h +64 -0
  86. data/src/event.cpp +7 -1
  87. data/src/event.h +1 -2
  88. data/src/ios/application.mm +5 -0
  89. data/src/ios/clipboard.mm +44 -0
  90. data/src/ios/event.h +6 -2
  91. data/src/ios/event.mm +31 -12
  92. data/src/ios/menu.mm +36 -0
  93. data/src/ios/view_controller.mm +45 -12
  94. data/src/ios/window.mm +6 -0
  95. data/src/menu.cpp +325 -0
  96. data/src/menu.h +65 -0
  97. data/src/osx/app_delegate.mm +74 -125
  98. data/src/osx/application.mm +16 -0
  99. data/src/osx/clipboard.mm +45 -0
  100. data/src/osx/event.mm +40 -10
  101. data/src/osx/menu.h +25 -0
  102. data/src/osx/menu.mm +372 -0
  103. data/src/osx/native_window.mm +27 -0
  104. data/src/osx/opengl_view.mm +51 -0
  105. data/src/osx/window.mm +11 -0
  106. data/src/pin.cpp +137 -0
  107. data/src/pointer.cpp +27 -16
  108. data/src/pointer.h +6 -0
  109. data/src/sdl/application.cpp +5 -0
  110. data/src/sdl/clipboard.cpp +39 -0
  111. data/src/sdl/event.cpp +20 -3
  112. data/src/sdl/event.h +6 -3
  113. data/src/sdl/menu.cpp +35 -0
  114. data/src/sdl/window.cpp +26 -8
  115. data/src/view.cpp +313 -52
  116. data/src/view.h +18 -2
  117. data/src/win32/application.cpp +5 -0
  118. data/src/win32/clipboard.cpp +210 -0
  119. data/src/win32/event.cpp +11 -1
  120. data/src/win32/event.h +2 -0
  121. data/src/win32/menu.cpp +352 -0
  122. data/src/win32/menu.h +27 -0
  123. data/src/win32/window.cpp +62 -0
  124. data/src/win32/window.h +3 -0
  125. data/src/window.cpp +235 -22
  126. data/src/window.h +13 -2
  127. data/src/world.cpp +77 -14
  128. data/src/world.h +9 -2
  129. data/test/helper.rb +7 -0
  130. data/test/test_application.rb +11 -0
  131. data/test/test_chase_constraint.rb +124 -0
  132. data/test/test_clipboard.rb +54 -0
  133. data/test/test_constraint.rb +186 -0
  134. data/test/test_key_event.rb +6 -0
  135. data/test/test_link_constraint.rb +239 -0
  136. data/test/test_menu.rb +207 -0
  137. data/test/test_pin.rb +65 -0
  138. data/test/test_pointer.rb +23 -9
  139. data/test/test_pointer_event.rb +1 -1
  140. data/test/test_snap_constraint.rb +142 -0
  141. data/test/test_view.rb +113 -23
  142. data/test/test_wheel_constraint.rb +127 -0
  143. data/test/test_wheel_event.rb +15 -9
  144. data/test/test_window.rb +10 -0
  145. metadata +82 -8
data/test/test_menu.rb ADDED
@@ -0,0 +1,207 @@
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, :command]
132
+ assert_equal 'c', m.shortcut_key
133
+ assert_equal [:command], m.shortcut_modifiers
134
+ end
135
+
136
+ def test_shortcut_key_keeps_modifiers()
137
+ m = menu
138
+ m.shortcut = [:c, :command, :shift]
139
+ assert_equal 'c', m.shortcut_key
140
+ assert_equal %i[command shift].sort, m.shortcut_modifiers.sort
141
+ m.shortcut_key = :v
142
+ assert_equal 'v', m.shortcut_key
143
+ assert_equal %i[command shift].sort, m.shortcut_modifiers.sort
144
+ end
145
+
146
+ def test_image()
147
+ m, img = menu, Reflex::Image.new(8, 8)
148
+ assert_nil m.image
149
+ m.image = img
150
+ assert_equal img, m.image
151
+ m.image = nil
152
+ assert_nil m.image
153
+
154
+ assert_raise(TypeError) {m.image = 1}
155
+ end
156
+
157
+ def test_separator()
158
+ assert_false menu(:File).separator?
159
+ assert_true menu('-').separator?
160
+ assert_true menu('---').separator?
161
+ assert_false menu('').separator?
162
+ end
163
+
164
+ def test_parent()
165
+ m = menu
166
+ c = m.add menu
167
+ assert_equal m, c.parent
168
+ assert_nil m.parent
169
+ m.remove c
170
+ assert_nil c.parent
171
+ end
172
+
173
+ def test_children()
174
+ m = menu
175
+ c = m.add menu
176
+ assert_equal [c], m.children
177
+ assert_equal c, m.first
178
+ end
179
+
180
+ def test_each_without_block()
181
+ m = menu
182
+ m.add menu(:A)
183
+ assert_kind_of Enumerator, m.each
184
+ assert_equal %w[A], m.each.map(&:label)
185
+ end
186
+
187
+ def test_nested()
188
+ root = menu
189
+ file = root.add menu(:File)
190
+ file.add menu(:Open)
191
+ assert_equal 'Open', root.first.first.label
192
+ end
193
+
194
+ def test_event_hooks()
195
+ m = menu
196
+ fired = []
197
+ %i[click show hide open_submenu close_submenu].each {|ev| m.on(ev) {|e| fired << ev}}
198
+ e = Reflex::UpdateEvent.new 0, 0
199
+ m.on_click e
200
+ m.on_show e
201
+ m.on_hide e
202
+ m.on_open_submenu e
203
+ m.on_close_submenu e
204
+ assert_equal %i[click show hide open_submenu close_submenu], fired
205
+ end
206
+
207
+ 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
@@ -15,8 +15,10 @@ class TestPointer < Test::Unit::TestCase
15
15
  DOWN = Reflex::Pointer::DOWN
16
16
  UP = Reflex::Pointer::UP
17
17
  MOVE = Reflex::Pointer::MOVE
18
- STAY = Reflex::Pointer::STAY
19
18
  CANCEL = Reflex::Pointer::CANCEL
19
+ ENTER = Reflex::Pointer::ENTER
20
+ LEAVE = Reflex::Pointer::LEAVE
21
+ STAY = Reflex::Pointer::STAY
20
22
 
21
23
  T = true
22
24
  F = false
@@ -44,7 +46,7 @@ class TestPointer < Test::Unit::TestCase
44
46
  assert_equal [2, 3], p.position.to_a
45
47
  assert_equal 2, p.x
46
48
  assert_equal 3, p.y
47
- assert_equal 4, p.modifiers
49
+ assert_equal [:shift], p.modifiers
48
50
  assert_equal 5, p.click_count
49
51
  assert_equal true, p.drag?
50
52
  assert_equal 6, p.time
@@ -99,28 +101,34 @@ class TestPointer < Test::Unit::TestCase
99
101
  def action(a)
100
102
  pointer(action: a).tap do |o|
101
103
  def o.test()
102
- [action, down?, up?, move?, cancel?, stay?]
104
+ [action, down?, up?, move?, cancel?, enter?, leave?, stay?]
103
105
  end
104
106
  end
105
107
  end
106
108
 
107
109
  o = action ACTION_NONE
108
- assert_equal [:none, F, F, F, F, F], o.test
110
+ assert_equal [:none, F, F, F, F, F, F, F], o.test
109
111
 
110
112
  o = action DOWN
111
- assert_equal [:down, T, F, F, F, F], o.test
113
+ assert_equal [:down, T, F, F, F, F, F, F], o.test
112
114
 
113
115
  o = action UP
114
- assert_equal [:up, F, T, F, F, F], o.test
116
+ assert_equal [:up, F, T, F, F, F, F, F], o.test
115
117
 
116
118
  o = action MOVE
117
- assert_equal [:move, F, F, T, F, F], o.test
119
+ assert_equal [:move, F, F, T, F, F, F, F], o.test
118
120
 
119
121
  o = action CANCEL
120
- assert_equal [:cancel, F, F, F, T, F], o.test
122
+ assert_equal [:cancel, F, F, F, T, F, F, F], o.test
123
+
124
+ o = action ENTER
125
+ assert_equal [:enter, F, F, F, F, T, F, F], o.test
126
+
127
+ o = action LEAVE
128
+ assert_equal [:leave, F, F, F, F, F, T, F], o.test
121
129
 
122
130
  o = action STAY
123
- assert_equal [:stay, F, F, F, F, T], o.test
131
+ assert_equal [:stay, F, F, F, F, F, F, T], o.test
124
132
  end
125
133
 
126
134
  def test_position()
@@ -133,6 +141,12 @@ class TestPointer < Test::Unit::TestCase
133
141
  assert_equal 2, pointer(position: [1, 2]).y
134
142
  end
135
143
 
144
+ def test_modifiers()
145
+ p = pointer modifiers: Reflex::MOD_SHIFT | Reflex::MOD_NUMPAD
146
+ assert_equal [:shift, :numpad], p.modifiers
147
+ assert_equal [:shift], p.modifiers(locks: false)
148
+ end
149
+
136
150
  def test_down()
137
151
  assert_equal 1, pointer(id: 1, action: DOWN).down.id # DOWN pointer's down() returns itself
138
152
  assert_nil pointer(id: 2, action: UP) .down
@@ -50,7 +50,7 @@ class TestPointerEvent < Test::Unit::TestCase
50
50
  assert_equal [2, 3], e.pos .to_a
51
51
  assert_equal 2, e.x
52
52
  assert_equal 3, e.y
53
- assert_equal 4, e.modifiers
53
+ assert_equal [:shift], e.modifiers
54
54
  assert_equal 5, e.click_count
55
55
  assert_equal true, e.drag?
56
56
  assert_equal 6, e.time
@@ -0,0 +1,142 @@
1
+ require_relative 'helper'
2
+
3
+
4
+ class TestSnapConstraint < Test::Unit::TestCase
5
+
6
+ def window()
7
+ Reflex::Window.new
8
+ end
9
+
10
+ def view(x = 0, y = 0, w = 50, h = 50, **options, &block)
11
+ Reflex::View.new(
12
+ frame: [x, y, w, h],
13
+ shape: Reflex::RectShape.new(density: 1),
14
+ **options, &block)
15
+ end
16
+
17
+ def point(...)
18
+ Reflex::Point.new(...)
19
+ end
20
+
21
+ def setup_views(win = window)
22
+ v1 = view 100, 100, dynamic: true
23
+ v2 = view 200, 100, static: true
24
+ win&.add v1
25
+ win&.add v2
26
+ [v1, v2, win, win&.root]
27
+ end
28
+
29
+ def test_initial_state()
30
+ v1, v2, = setup_views
31
+
32
+ assert_equal v1, v1.snap(v2) .pins[0].view
33
+ assert_equal v2, v1.snap(v2) .pins[1].view
34
+ assert_nil v1.snap(v2) .angle
35
+ assert_equal 1..1, v1.snap(v2, angle: 1) .angle
36
+ assert_equal 2..3, v1.snap(v2, angle: 2..3) .angle
37
+ assert_nil v1.snap(v2) .motor
38
+ assert_equal 4, v1.snap(v2, motor: 4) .motor
39
+ assert_nil v1.snap(v2) .force
40
+ assert_equal 6, v1.snap(v2, force: 6) .force
41
+ assert_nil v1.snap(v2) .spring
42
+ assert_equal 5, v1.snap(v2, spring: 5) .spring
43
+ assert_in_delta 0.7, v1.snap(v2) .damping
44
+ assert_in_delta 0.1, v1.snap(v2, damping: 0.1).damping
45
+ assert_false v1.snap(v2) .collide?
46
+ assert_true v1.snap(v2) .active?
47
+ assert_false v1.snap(v2) .removed?
48
+ end
49
+
50
+ def test_snap_keeps_positions()
51
+ v1, v2, _, root = setup_views
52
+ v1.angle = 45
53
+
54
+ v1.snap v2 # nothing moves
55
+
56
+ 10.times {root.update_world}
57
+ assert_equal_point point(0), v1.linear_velocity
58
+ end
59
+
60
+ def test_snap_pulls_together()
61
+ v1, v2, _, root = setup_views
62
+
63
+ v1.pin(25, 25).snap v2.pin(25, 25), angle: 0, spring: 4
64
+
65
+ root.update_world
66
+ assert_operator v1.linear_velocity.x, :>, 0
67
+ end
68
+
69
+ def test_snap_to_world()
70
+ v1, _, _, root = setup_views
71
+ root.gravity 0, 900
72
+
73
+ c = v1.snap
74
+ assert_nil c.pins[1].view
75
+
76
+ 60.times {root.update_world}
77
+ assert_in_delta 100, v1.frame.y, 0.01 # hangs against gravity
78
+ end
79
+
80
+ def test_weld_fixes_angle()
81
+ v1, v2, _, root = setup_views
82
+
83
+ v1.snap v2, angle: 0 # welds and fixes the angle
84
+ v1.angular_velocity = 90
85
+
86
+ 10.times {root.update_world}
87
+ assert_in_delta 0, v1.angular_velocity
88
+ end
89
+
90
+ def test_angle()
91
+ v1, v2, = setup_views
92
+
93
+ c = v1.snap v2, angle: -30..90
94
+ assert_equal(-30..90, c.angle)
95
+
96
+ c.angle = 0
97
+ assert_equal 0..0, c.angle
98
+
99
+ c.angle = nil
100
+ assert_nil c.angle
101
+
102
+ assert_raise(ArgumentError) {c.angle = 'invalid'}
103
+ end
104
+
105
+ def test_motor()
106
+ v1, v2, _, root = setup_views
107
+
108
+ c = v1.snap v2, motor: 90
109
+ assert_equal 90, c.motor
110
+
111
+ 3.times {root.update_world}
112
+ assert_in_delta 90, v1.angular_velocity
113
+
114
+ c.motor = nil
115
+ assert_nil c.motor
116
+ end
117
+
118
+ def test_force()
119
+ v1, v2, = setup_views
120
+
121
+ c = v1.snap v2, motor: 90, force: 500
122
+ assert_equal 500, c.force
123
+
124
+ c.force = nil
125
+ assert_nil c.force
126
+
127
+ c.force = 100
128
+ assert_equal 100, c.force
129
+
130
+ assert_raise(ArgumentError) {c.force = -1}
131
+ end
132
+
133
+ def test_force_limits_the_motor()
134
+ v1, v2, _, root = setup_views
135
+
136
+ v1.snap v2, motor: 90, force: 0 # a powerless motor can not spin
137
+
138
+ 3.times {root.update_world}
139
+ assert_in_delta 0, v1.angular_velocity
140
+ end
141
+
142
+ end# TestSnapConstraint
data/test/test_view.rb CHANGED
@@ -85,12 +85,36 @@ class TestView < Test::Unit::TestCase
85
85
  end
86
86
 
87
87
  def test_add_child()
88
+ view.tap do |v|
89
+ v.add view(name: :a)
90
+ v.add view(name: :b)
91
+ v.add view(name: :c), index: 1
92
+ assert_equal %w[a c b], v.children.map(&:name)
93
+ end
94
+
95
+ view.tap do |v|
96
+ v.add view(name: :a)
97
+ v.add view(name: :b), index: 0
98
+ v.add view(name: :c), index: v.children.to_a.size
99
+ assert_equal %w[b a c], v.children.map(&:name)
100
+ end
101
+
102
+ view.tap do |v|
103
+ v.add view(name: :a)
104
+ v.add view(name: :b), index: 99
105
+ v.add view(name: :c), index: -1
106
+ v.add view(name: :d), index: nil
107
+ assert_equal %w[a b c d], v.children.map(&:name)
108
+ end
109
+
110
+ view.tap do |v|
111
+ assert_nothing_raised {v.add_child view}
112
+ assert_raise(ArgumentError) {v.add_child v}
113
+ end
114
+
88
115
  assert_raise(ArgumentError) {view.add_child}
89
- assert_raise(TypeError) {view.add_child nil}
90
- assert_raise(TypeError) {view.add_child 1}
91
- v = view
92
- assert_raise(ArgumentError) {v.add_child v}
93
- assert_nothing_raised {v.add_child view}
116
+ assert_raise(TypeError) {view.add_child nil}
117
+ assert_raise(TypeError) {view.add_child 1}
94
118
  end
95
119
 
96
120
  def test_remove_child()
@@ -144,6 +168,18 @@ class TestView < Test::Unit::TestCase
144
168
  assert_not_includes v.find_styles(selector name: :N), s
145
169
  end
146
170
 
171
+ def test_find_styles()
172
+ v, s = view, style(name: :N1, tag: :T1)
173
+ s.add_tag :T2
174
+ v.add_style s
175
+
176
+ assert_includes v.find_styles(:N1), s
177
+ assert_includes v.find_styles(selector tag: :T1), s
178
+ assert_includes v.find_styles(selector tags: [:T1, :T2]), s
179
+ assert_empty v.find_styles(selector tags: [:T1, :X])
180
+ assert_empty v.find_styles(selector tag: :X)
181
+ end
182
+
147
183
  def test_shape()
148
184
  s = shape
149
185
  assert_equal 0, s.density
@@ -194,26 +230,80 @@ class TestView < Test::Unit::TestCase
194
230
  end
195
231
 
196
232
  def test_add_remove_shape()
197
- s = shape name: :S
198
- s.density = 1
199
- assert_equal 1, s.density
200
-
201
- v = view
202
- assert_equal 0, v.shapes.to_a.size
203
-
233
+ view.tap do |v|
234
+ s = shape name: :S
235
+ s.density = 1
236
+ assert_equal 1, s.density
237
+
238
+ assert_equal 0, v.shapes.to_a.size
239
+
240
+ v.add_shape s
241
+ assert_equal 1, v.shapes.to_a.size
242
+ assert_includes v.find_shapes(selector name: :S), s
243
+ assert_equal 1, v.find_shapes(selector name: :S).first.density
244
+
245
+ v.remove_shape s
246
+ assert_equal 0, v.shapes.to_a.size
247
+ assert_not_includes v.find_shapes(selector name: :S), s
248
+
249
+ v.add_shape s
250
+ assert_equal 1, v.shapes.to_a.size
251
+ v.clear_shapes
252
+ assert_equal 0, v.shapes.to_a.size
253
+ end
254
+
255
+ view.tap do |v|
256
+ v.add_shape shape(name: :a)
257
+ v.add_shape shape(name: :b)
258
+ v.add_shape shape(name: :c), index: 1
259
+ assert_equal %w[a c b], v.shapes.map(&:name)
260
+ end
261
+
262
+ view.tap do |v|
263
+ v.add_shape shape(name: :a)
264
+ v.add_shape shape(name: :b), index: 0
265
+ v.add_shape shape(name: :c), index: v.shapes.to_a.size
266
+ assert_equal %w[b a c], v.shapes.map(&:name)
267
+ end
268
+
269
+ view.tap do |v|
270
+ v.add_shape shape(name: :a)
271
+ v.add_shape shape(name: :b), index: 99
272
+ v.add_shape shape(name: :c), index: -1
273
+ v.add_shape shape(name: :d), index: nil
274
+ assert_equal %w[a b c d], v.shapes.map(&:name)
275
+ end
276
+ end
277
+
278
+ def test_find_shapes()
279
+ v, s = view, shape(name: :N1, tag: :T1)
280
+ s.add_tag :T2
204
281
  v.add_shape s
205
- assert_equal 1, v.shapes.to_a.size
206
- assert_includes v.find_shapes(selector name: :S), s
207
- assert_equal 1, v.find_shapes(selector name: :S).first.density
208
-
209
- v.remove_shape s
210
- assert_equal 0, v.shapes.to_a.size
211
- assert_not_includes v.find_shapes(selector name: :S), s
212
282
 
213
- v.add_shape s
214
- assert_equal 1, v.shapes.to_a.size
215
- v.clear_shapes
216
- assert_equal 0, v.shapes.to_a.size
283
+ assert_includes v.find_shapes(:N1), s
284
+ assert_includes v.find_shapes(selector tag: :T1), s
285
+ assert_includes v.find_shapes(selector tags: [:T1, :T2]), s
286
+ assert_empty v.find_shapes(selector tags: [:T1, :X])
287
+ assert_empty v.find_shapes(selector tag: :X)
288
+ end
289
+
290
+ def test_find_constraints()
291
+ win = window
292
+ v1 = view frame: [100, 100, 50, 50], shape: shape(density: 1), dynamic: true
293
+ v2 = view frame: [200, 100, 50, 50], shape: shape(density: 1), static: true
294
+ win.add v1
295
+ win.add v2
296
+
297
+ c = v1.link v2, name: :N1, tag: :T1
298
+ c.add_tag :T2
299
+
300
+ [v1, v2].each do |v|
301
+ assert_includes v.find_constraints(:N1), c
302
+ assert_includes v.find_constraints(selector tag: :T1), c
303
+ assert_includes v.find_constraints(selector tags: [:T1, :T2]), c
304
+ assert_empty v.find_constraints(selector tags: [:T2, :X])
305
+ assert_empty v.find_constraints(selector tags: [:X])
306
+ end
217
307
  end
218
308
 
219
309
  def test_name()