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
data/src/view.cpp CHANGED
@@ -4,6 +4,7 @@
4
4
  #include <limits.h>
5
5
  #include <string.h>
6
6
  #include <assert.h>
7
+ #include <math.h>
7
8
  #include <memory>
8
9
  #include <algorithm>
9
10
  #include <rays/matrix.h>
@@ -20,6 +21,7 @@
20
21
  #include "world.h"
21
22
  #include "body.h"
22
23
  #include "fixture.h"
24
+ #include "constraint.h"
23
25
 
24
26
 
25
27
  namespace Reflex
@@ -39,29 +41,23 @@ namespace Reflex
39
41
  enum Flag
40
42
  {
41
43
 
42
- UPDATING = Xot::bit(1, FLAG_LAST),
44
+ NO_SHAPE = Xot::bit(1, FLAG_LAST),
43
45
 
44
- NO_SHAPE = Xot::bit(2, FLAG_LAST),
46
+ HAS_VARIABLE_LENGTHS = Xot::bit(2, FLAG_LAST),
45
47
 
46
- HAS_VARIABLE_LENGTHS = Xot::bit(3, FLAG_LAST),
48
+ REDRAW = Xot::bit(3, FLAG_LAST),
47
49
 
48
- HAS_CHILDREN_TO_REMOVE = Xot::bit(4, FLAG_LAST),
50
+ APPLY_STYLE = Xot::bit(4, FLAG_LAST),
49
51
 
50
- REMOVE_FROM_PARENT = Xot::bit(5, FLAG_LAST),
52
+ UPDATE_STYLE = Xot::bit(5, FLAG_LAST),
51
53
 
52
- REDRAW = Xot::bit(6, FLAG_LAST),
54
+ UPDATE_SHAPES = Xot::bit(6, FLAG_LAST),
53
55
 
54
- APPLY_STYLE = Xot::bit(7, FLAG_LAST),
56
+ UPDATE_LAYOUT = Xot::bit(7, FLAG_LAST),
55
57
 
56
- UPDATE_STYLE = Xot::bit(8, FLAG_LAST),
58
+ SORT_CHILDREN = Xot::bit(8, FLAG_LAST),
57
59
 
58
- UPDATE_SHAPES = Xot::bit(9, FLAG_LAST),
59
-
60
- UPDATE_LAYOUT = Xot::bit(10, FLAG_LAST),
61
-
62
- SORT_CHILDREN = Xot::bit(11, FLAG_LAST),
63
-
64
- FIT_TO_CONTENT = Xot::bit(12, FLAG_LAST),
60
+ FIT_TO_CONTENT = Xot::bit(9, FLAG_LAST),
65
61
 
66
62
  };// Flag
67
63
 
@@ -81,38 +77,42 @@ namespace Reflex
81
77
 
82
78
  ushort child_index = 0;
83
79
 
80
+ int loop_depth = 0;
81
+
84
82
  uint flags =
85
83
  FLAG_CLIP | FLAG_RESIZE_TO_FIT | REDRAW | UPDATE_LAYOUT | UPDATE_STYLE;
86
84
 
87
- std::unique_ptr<Point> ppivot;
85
+ std::unique_ptr<Point> ppivot;
88
86
 
89
- std::unique_ptr<Point> pscroll;
87
+ std::unique_ptr<Point> pscroll;
90
88
 
91
- SelectorPtr pselector;
89
+ SelectorPtr pselector;
92
90
 
93
- std::unique_ptr<SelectorSet> pselectors_for_update;
91
+ std::unique_ptr<SelectorSet> pselectors_for_update;
94
92
 
95
- std::unique_ptr<Image> pcache_image;
93
+ std::unique_ptr<Image> pdraw_cache;
96
94
 
97
- std::unique_ptr<Timers> ptimers;
95
+ std::unique_ptr<Timers> ptimers;
98
96
 
99
- std::unique_ptr<Style> pstyle;
97
+ std::unique_ptr<Style> pstyle;
100
98
 
101
- std::unique_ptr<StyleList> pstyles;
99
+ std::unique_ptr<StyleList> pstyles;
102
100
 
103
- Shape::Ref pshape;
101
+ Shape::Ref pshape;
104
102
 
105
- std::unique_ptr<ShapeList> pshapes;
103
+ std::unique_ptr<ShapeList> pshapes;
106
104
 
107
- Filter::Ref pfilter;
105
+ Filter::Ref pfilter;
108
106
 
109
- std::unique_ptr<Body> pbody;
107
+ std::unique_ptr<Body> pbody;
110
108
 
111
- std::unique_ptr<World> pchild_world;
109
+ std::unique_ptr<ConstraintList> pconstraints;
112
110
 
113
- std::unique_ptr<ChildList> pchildren;
111
+ std::unique_ptr<World> pchild_world;
114
112
 
115
- std::unique_ptr<ChildList> pchildren_sorted;
113
+ std::unique_ptr<ChildList> pchildren;
114
+
115
+ std::unique_ptr<ChildList> pchildren_for_loop;
116
116
 
117
117
  Point& pivot ()
118
118
  {
@@ -176,6 +176,24 @@ namespace Reflex
176
176
  return *pshapes;
177
177
  }
178
178
 
179
+ ConstraintList& constraints ()
180
+ {
181
+ if (!pconstraints) pconstraints.reset(new ConstraintList);
182
+ return *pconstraints;
183
+ }
184
+
185
+ void sever_constraints ()
186
+ {
187
+ if (!pconstraints) return;
188
+
189
+ ConstraintList list;
190
+ list.swap(*pconstraints);
191
+ for (auto& constraint : list)
192
+ Constraint_sever(constraint.get());
193
+
194
+ pconstraints.reset();
195
+ }
196
+
179
197
  template <typename FUN>
180
198
  void each_shape (FUN fun)
181
199
  {
@@ -203,6 +221,17 @@ namespace Reflex
203
221
  });
204
222
  }
205
223
 
224
+ void update_constraints ()
225
+ {
226
+ if (!pconstraints) return;
227
+
228
+ for (auto& constraint : *pconstraints)
229
+ {
230
+ Constraint_deactivate(constraint.get());
231
+ Constraint_activate(constraint.get());
232
+ }
233
+ }
234
+
206
235
  void resize_shapes (FrameEvent* e)
207
236
  {
208
237
  each_shape([=](Shape* shape)
@@ -287,6 +316,7 @@ namespace Reflex
287
316
  }
288
317
 
289
318
  update_shapes(true);
319
+ update_constraints();
290
320
  }
291
321
 
292
322
  World* parent_world (bool create = true)
@@ -331,24 +361,30 @@ namespace Reflex
331
361
  view->remove_child(wall.get());
332
362
  }
333
363
 
334
- ChildList* children (bool create = false, bool sort = false)
364
+ ChildList* children (bool create = false)
335
365
  {
336
- if (!pchildren)
337
- {
338
- if (!create) return NULL;
339
- pchildren.reset(new ChildList);
340
- }
341
-
342
- if (sort && check_and_remove_flag(SORT_CHILDREN))
343
- do_sort_children();
366
+ if (!pchildren && create) pchildren.reset(new ChildList);
367
+ return pchildren.get();
368
+ }
344
369
 
345
- return sort && pchildren_sorted ? pchildren_sorted.get() : pchildren.get();
370
+ ChildList* children_for_loop ()
371
+ {
372
+ if (pchildren && !pchildren_for_loop) do_sort_children();
373
+ return pchildren_for_loop.get();
346
374
  }
347
375
 
348
- void sort_children (bool order_only = false)
376
+ void sort_children ()
349
377
  {
350
378
  add_flag(SORT_CHILDREN);
351
- if (!order_only && pchildren_sorted) pchildren_sorted.reset();
379
+ }
380
+
381
+ void update_children_for_loop (View* view)
382
+ {
383
+ if (!has_flag(SORT_CHILDREN) || loop_depth != 0)
384
+ return;
385
+
386
+ do_sort_children();
387
+ view->redraw();
352
388
  }
353
389
 
354
390
  void add_flag (uint flag)
@@ -361,6 +397,11 @@ namespace Reflex
361
397
  Xot::remove_flag(&flags, flag);
362
398
  }
363
399
 
400
+ void update_flag (uint flag, bool add)
401
+ {
402
+ Xot::update_flag(&flags, flag, add);
403
+ }
404
+
364
405
  bool has_flag (uint flag) const
365
406
  {
366
407
  return Xot::has_flag(flags, flag);
@@ -375,7 +416,19 @@ namespace Reflex
375
416
 
376
417
  void do_sort_children ()
377
418
  {
378
- auto& children = *pchildren;
419
+ remove_flag(SORT_CHILDREN);
420
+
421
+ if (!pchildren || pchildren->empty())
422
+ {
423
+ pchildren_for_loop.reset();
424
+ return;
425
+ }
426
+
427
+ if (!pchildren_for_loop)
428
+ pchildren_for_loop.reset(new ChildList);
429
+
430
+ auto& children = *pchildren;
431
+ *pchildren_for_loop = children;
379
432
 
380
433
  size_t size = children.size();
381
434
  if (size >= USHRT_MAX)
@@ -389,20 +442,10 @@ namespace Reflex
389
442
  have_z |= child->frame().z != 0;
390
443
  }
391
444
 
392
- if (!have_z)
393
- {
394
- pchildren_sorted.reset();
395
- return;
396
- }
397
-
398
- if (!pchildren_sorted)
399
- {
400
- pchildren_sorted.reset(
401
- new ChildList(children.begin(), children.end()));
402
- }
445
+ if (!have_z) return;
403
446
 
404
447
  std::sort(
405
- pchildren_sorted->begin(), pchildren_sorted->end(),
448
+ pchildren_for_loop->begin(), pchildren_for_loop->end(),
406
449
  [](const auto& a, const auto& b)
407
450
  {
408
451
  auto *aa = a->self.get(), *bb = b->self.get();
@@ -706,8 +749,64 @@ namespace Reflex
706
749
  };// LayoutContext
707
750
 
708
751
 
709
- void
710
- View_set_window (View* view, Window* window)
752
+ struct LoopDepthGuard
753
+ {
754
+
755
+ View::Data* self;
756
+
757
+ LoopDepthGuard (View::Data* self)
758
+ : self(self)
759
+ {
760
+ ++self->loop_depth;
761
+ }
762
+
763
+ ~LoopDepthGuard ()
764
+ {
765
+ --self->loop_depth;
766
+ }
767
+
768
+ };// LoopDepthGuard
769
+
770
+
771
+ static void
772
+ call_children (View* parent, std::function<bool(View*)> fun)
773
+ {
774
+ auto* children = parent->self->children_for_loop();
775
+ if (!children) return;
776
+
777
+ LoopDepthGuard depth_guard(parent->self.get());
778
+
779
+ for (auto it = children->rbegin(), end = children->rend(); it != end; ++it)
780
+ {
781
+ View::Ref child = *it;
782
+ if (!child) continue;// removed since the last frame
783
+
784
+ if (!fun(child.get()))
785
+ break;
786
+ }
787
+ }
788
+
789
+ static void
790
+ call_children_unsafe (View* parent, std::function<bool(View*)> fun)
791
+ {
792
+ auto* children = parent->self->children();
793
+ if (!children) return;
794
+
795
+ LoopDepthGuard depth_guard(parent->self.get());
796
+
797
+ for (size_t i = children->size(); i-- > 0;)
798
+ {
799
+ if (i >= children->size())
800
+ continue;// a handler shrank the list
801
+
802
+ View::Ref child = (*children)[i];
803
+ if (!fun(child.get()))
804
+ break;
805
+ }
806
+ }
807
+
808
+ static void
809
+ set_window (View* view, Window* window)
711
810
  {
712
811
  if (!view)
713
812
  argument_error(__FILE__, __LINE__);
@@ -726,7 +825,7 @@ namespace Reflex
726
825
  if (children)
727
826
  {
728
827
  for (auto& child : *children)
729
- View_set_window(child.get(), window);
828
+ set_window(child.get(), window);
730
829
  }
731
830
 
732
831
  if (view->self->window)
@@ -737,6 +836,28 @@ namespace Reflex
737
836
  }
738
837
  }
739
838
 
839
+ void
840
+ View_set_window (View* view, Window* window)
841
+ {
842
+ if (!view)
843
+ argument_error(__FILE__, __LINE__);
844
+
845
+ Window* old = view->self->window;
846
+ if (old && old->active())
847
+ {
848
+ Event e;
849
+ View_deactivate_tree(view, &e);
850
+ }
851
+
852
+ set_window(view, window);
853
+
854
+ if (window && window->active())
855
+ {
856
+ Event e;
857
+ View_activate_tree(view, &e);
858
+ }
859
+ }
860
+
740
861
  static void
741
862
  apply_style_to_children_have_variable_lengths (View* parent)
742
863
  {
@@ -797,7 +918,7 @@ namespace Reflex
797
918
  self->update_body_frame();
798
919
 
799
920
  if (moved && event.dz() != 0 && self->parent)
800
- self->parent->self->sort_children(true);
921
+ self->parent->self->sort_children();
801
922
 
802
923
  if ((moved || resized) && self->parent)
803
924
  self->parent->self->add_flag(View::Data::FIT_TO_CONTENT);
@@ -832,18 +953,103 @@ namespace Reflex
832
953
  return create ? &view->self->body() : view->self->pbody.get();
833
954
  }
834
955
 
956
+ const Body*
957
+ View_get_body (const View* view)
958
+ {
959
+ return View_get_body(const_cast<View*>(view), false);
960
+ }
961
+
962
+ void
963
+ View_add_constraint (View* view, Constraint* constraint)
964
+ {
965
+ if (!view || !constraint)
966
+ argument_error(__FILE__, __LINE__);
967
+
968
+ if (constraint->is_removed())
969
+ invalid_state_error(__FILE__, __LINE__, "constraint is already removed");
970
+
971
+ if (constraint->view(0) != view)
972
+ argument_error(__FILE__, __LINE__, "the constraint does not belong to this view");
973
+
974
+ auto& list = view->self->constraints();
975
+ if (std::find(list.begin(), list.end(), constraint) != list.end())
976
+ invalid_state_error(__FILE__, __LINE__, "the constraint is already added");
977
+
978
+ // the mismatch is not detectable before activation because
979
+ // activating is what creates the missing bodies
980
+ if (
981
+ !Constraint_activate(constraint) &&
982
+ Constraint_has_world_mismatch(constraint))
983
+ {
984
+ physics_error(__FILE__, __LINE__, "the views belong to different worlds");
985
+ }
986
+
987
+ list.push_back(constraint);
988
+ View* view1 = constraint->view(1);
989
+ if (view1) view1->self->constraints().push_back(constraint);
990
+ }
991
+
992
+ void
993
+ View_remove_constraint (View* view, Constraint* constraint)
994
+ {
995
+ if (!view || !constraint)
996
+ argument_error(__FILE__, __LINE__);
997
+
998
+ auto* list = view->self->pconstraints.get();
999
+ if (!list) return;
1000
+
1001
+ auto it = std::find(list->begin(), list->end(), constraint);
1002
+ if (it != list->end()) list->erase(it);
1003
+
1004
+ if (list->empty()) view->self->pconstraints.reset();
1005
+ }
1006
+
835
1007
  bool
836
1008
  View_is_active (const View& view)
837
1009
  {
838
1010
  return view.self->window;
839
1011
  }
840
1012
 
1013
+ void
1014
+ View_activate_tree (View* view, Event* event)
1015
+ {
1016
+ if (!view)
1017
+ argument_error(__FILE__, __LINE__);
1018
+
1019
+ Event e = event->dup();
1020
+ view->on_activate(&e);
1021
+ if (e.is_blocked()) return;
1022
+
1023
+ call_children_unsafe(view, [&](View* child) {
1024
+ View_activate_tree(child, &e);
1025
+ return !e.is_blocked();
1026
+ });
1027
+ }
1028
+
1029
+ void
1030
+ View_deactivate_tree (View* view, Event* event)
1031
+ {
1032
+ if (!view)
1033
+ argument_error(__FILE__, __LINE__);
1034
+
1035
+ Event e = event->dup();
1036
+
1037
+ call_children_unsafe(view, [&](View* child) {
1038
+ View_deactivate_tree(child, &e);
1039
+ return !e.is_blocked();
1040
+ });
1041
+
1042
+ if (e.is_blocked()) return;
1043
+
1044
+ view->on_deactivate(&e);
1045
+ }
1046
+
841
1047
  static void
842
1048
  find_all_children (
843
1049
  View::ChildList* result, const View* view, const Selector& selector,
844
1050
  bool recursive)
845
1051
  {
846
- View::ChildList* children = view->self->children();
1052
+ auto* children = view->self->children();
847
1053
  if (!children) return;
848
1054
 
849
1055
  for (auto& child : *children)
@@ -869,7 +1075,7 @@ namespace Reflex
869
1075
  {
870
1076
  for (auto& style : *pstyles)
871
1077
  {
872
- if (selector.contains(style.selector()))
1078
+ if (style.selector().contains(selector))
873
1079
  result->push_back(style);
874
1080
  }
875
1081
  }
@@ -933,14 +1139,14 @@ namespace Reflex
933
1139
  }
934
1140
 
935
1141
  static void
936
- update_child_world (View* view, float dt)
1142
+ update_child_world (View* view)
937
1143
  {
938
1144
  View::Data* self = view->self.get();
939
1145
 
940
1146
  World* child_world = self->pchild_world.get();
941
1147
  if (!child_world) return;
942
1148
 
943
- child_world->on_update(dt);
1149
+ child_world->on_update();
944
1150
 
945
1151
  View::ChildList* children = self->children();
946
1152
  if (children)
@@ -1019,11 +1225,9 @@ namespace Reflex
1019
1225
  Style_override(pstyle, st);
1020
1226
  }
1021
1227
 
1022
- const Style& style = View_get_style(view);
1023
- if (Style_has_variable_lengths(style))
1024
- self->add_flag(View::Data::HAS_VARIABLE_LENGTHS);
1025
- else
1026
- self->remove_flag(View::Data::HAS_VARIABLE_LENGTHS);
1228
+ self->update_flag(
1229
+ View::Data::HAS_VARIABLE_LENGTHS,
1230
+ Style_has_variable_lengths(View_get_style(view)));
1027
1231
 
1028
1232
  self->add_flag(View::Data::APPLY_STYLE);
1029
1233
  }
@@ -1052,20 +1256,6 @@ namespace Reflex
1052
1256
  }
1053
1257
  }
1054
1258
 
1055
- static void
1056
- remove_children (View* view, View::ChildList* children)
1057
- {
1058
- assert(children);
1059
-
1060
- int size = (int) children->size();
1061
- for (int i = size - 1; i >= 0; --i)
1062
- {
1063
- View* child = (*children)[i].get();
1064
- if (child->self->check_and_remove_flag(View::Data::REMOVE_FROM_PARENT))
1065
- view->remove_child(child);
1066
- }
1067
- }
1068
-
1069
1259
  void
1070
1260
  View_update_tree (View* view, const UpdateEvent& event)
1071
1261
  {
@@ -1074,20 +1264,24 @@ namespace Reflex
1074
1264
 
1075
1265
  View::Data* self = view->self.get();
1076
1266
 
1077
- self->add_flag(View::Data::UPDATING);
1267
+ self->update_children_for_loop(view);
1078
1268
 
1079
1269
  fire_timers(view, event.now());
1080
1270
 
1081
- View::ChildList* children = self->children();
1271
+ View::ChildList* children = self->children_for_loop();
1082
1272
  if (children)
1083
1273
  {
1084
- size_t size = children->size();
1085
- for (size_t i = 0; i < size; ++i)
1086
- View_update_tree((*children)[i].get(), event);
1274
+ LoopDepthGuard depth_guard(self);
1275
+
1276
+ for (View::Ref child : *children)
1277
+ {
1278
+ if (!child) continue;// removed since the last frame
1279
+ View_update_tree(child.get(), event);
1280
+ }
1087
1281
  }
1088
1282
 
1089
1283
  update_view_shapes(view);
1090
- update_child_world(view, event.dt());
1284
+ update_child_world(view);
1091
1285
 
1092
1286
  UpdateEvent e = event.dup();
1093
1287
  view->on_update(&e);
@@ -1106,42 +1300,36 @@ namespace Reflex
1106
1300
  if (self->check_and_remove_flag(View::Data::FIT_TO_CONTENT))
1107
1301
  fit_view_to_content(view);
1108
1302
 
1109
- self->remove_flag(View::Data::UPDATING);
1110
-
1111
- if (self->check_and_remove_flag(View::Data::HAS_CHILDREN_TO_REMOVE))
1112
- remove_children(view, children);
1113
1303
  }
1114
1304
 
1115
1305
  static bool
1116
- use_cache (View* view)
1306
+ use_draw_cache (const View::Data& self)
1117
1307
  {
1118
- View::Data* self = view->self.get();
1119
-
1120
- return
1121
- self->has_flag(View::FLAG_CACHE) ||
1122
- (self->pfilter && *self->pfilter);
1308
+ return self.has_flag(View::FLAG_DRAW_CACHE) || (self.pfilter && *self.pfilter);
1123
1309
  }
1124
1310
 
1125
1311
  static bool
1126
- reset_cache_image (View* view, const Painter& painter)
1312
+ setup_draw_cache (View::Data* self, float density)
1127
1313
  {
1128
- assert(use_cache(view));
1129
- View::Data* self = view->self.get();
1314
+ int w = (int) ceil(self->frame.width);
1315
+ int h = (int) ceil(self->frame.height);
1316
+ if (w == 0 || h == 0 || !use_draw_cache(*self))
1317
+ {
1318
+ self->pdraw_cache.reset();
1319
+ return false;
1320
+ }
1130
1321
 
1131
- Image* image = self->pcache_image.get();
1132
- int w = ceil(self->frame.width);
1133
- int h = ceil(self->frame.height);
1322
+ Image* image = self->pdraw_cache.get();
1134
1323
  if (
1135
1324
  image &&
1136
1325
  image->width() == w &&
1137
1326
  image->height() == h &&
1138
- image->pixel_density() == painter.pixel_density())
1327
+ image->pixel_density() == density)
1139
1328
  {
1140
1329
  return false;
1141
1330
  }
1142
1331
 
1143
- self->pcache_image.reset(
1144
- new Image(w, h, Rays::RGBA, painter.pixel_density()));
1332
+ self->pdraw_cache.reset(new Image(w, h, Rays::RGBA, density));
1145
1333
  return true;
1146
1334
  }
1147
1335
 
@@ -1194,7 +1382,7 @@ namespace Reflex
1194
1382
 
1195
1383
  static void
1196
1384
  draw_view (
1197
- View* view, DrawEvent* event, const Point& offset, const Bounds& clip)
1385
+ View* view, DrawEvent* event, const Point& offset, const Bounds& clip, float scale)
1198
1386
  {
1199
1387
  View::Data* self = view->self.get();
1200
1388
 
@@ -1212,13 +1400,17 @@ namespace Reflex
1212
1400
 
1213
1401
  if (event->is_blocked()) return;
1214
1402
 
1215
- View::ChildList* children = self->children(false, true);
1403
+ View::ChildList* children = self->children_for_loop();
1216
1404
  if (children)
1217
1405
  {
1218
- for (auto& child : *children)
1406
+ LoopDepthGuard depth_guard(self);
1407
+
1408
+ for (View::Ref child : *children)
1219
1409
  {
1410
+ if (!child) continue;
1411
+
1220
1412
  if (event->bounds() & child->self->frame)
1221
- View_draw_tree(child.get(), event, offset, clip);
1413
+ View_draw_tree(child.get(), event, offset, clip, scale);
1222
1414
  }
1223
1415
  }
1224
1416
 
@@ -1235,12 +1427,12 @@ namespace Reflex
1235
1427
  draw_view_to_cache (View* view, DrawEvent* event)
1236
1428
  {
1237
1429
  Painter* view_painter = event->painter();
1238
- Painter cache_painter = view->self->pcache_image->painter();
1430
+ Painter cache_painter = view->self->pdraw_cache->painter();
1239
1431
 
1240
1432
  DrawEvent_set_painter(event, &cache_painter);
1241
1433
 
1242
1434
  cache_painter.begin();
1243
- draw_view(view, event, 0, event->bounds());
1435
+ draw_view(view, event, 0, event->bounds(), 1);
1244
1436
  cache_painter.end();
1245
1437
 
1246
1438
  DrawEvent_set_painter(event, view_painter);
@@ -1251,40 +1443,32 @@ namespace Reflex
1251
1443
  {
1252
1444
  View::Data* self = view->self.get();
1253
1445
 
1254
- if (!use_cache(view))
1255
- {
1256
- self->pcache_image.reset();
1257
- return false;
1258
- }
1259
-
1260
1446
  Painter* painter = event->painter();
1447
+ bool created = setup_draw_cache(self, painter->pixel_density());
1448
+ if (!self->pdraw_cache)
1449
+ return false;
1261
1450
 
1262
- if (reset_cache_image(view, *painter) || redraw)
1263
- {
1264
- if (!self->pcache_image)
1265
- return false;
1266
-
1451
+ if (created || redraw)
1267
1452
  draw_view_to_cache(view, event);
1268
- }
1269
1453
 
1270
1454
  painter->push_state();
1271
- painter->set_fill(1);
1272
- painter->no_stroke();
1273
- painter->no_shader();
1274
-
1275
- if (self->pfilter && *self->pfilter)
1276
- self->pfilter->apply(painter, *self->pcache_image);
1277
- else
1278
- painter->image(*self->pcache_image, event->bounds());
1455
+ {
1456
+ painter->set_fill(1);
1457
+ painter->no_stroke();
1458
+ painter->no_shader();
1279
1459
 
1460
+ if (self->pfilter && *self->pfilter)
1461
+ self->pfilter->apply(painter, *self->pdraw_cache);
1462
+ else
1463
+ painter->image(*self->pdraw_cache, event->bounds());
1464
+ }
1280
1465
  painter->pop_state();
1281
-
1282
1466
  return true;
1283
1467
  }
1284
1468
 
1285
1469
  void
1286
1470
  View_draw_tree (
1287
- View* view, DrawEvent* event, const Point& offset, const Bounds& clip)
1471
+ View* view, DrawEvent* event, const Point& offset, Bounds clip, float scale)
1288
1472
  {
1289
1473
  if (!view)
1290
1474
  argument_error(__FILE__, __LINE__);
@@ -1300,9 +1484,17 @@ namespace Reflex
1300
1484
  return;
1301
1485
 
1302
1486
  Bounds bounds = self->frame;
1303
- Point pos = bounds.position();
1304
- Bounds clip2 = bounds.dup().move_by(offset) & clip;
1487
+ if (clip)
1488
+ {
1489
+ // clipping is applied via glScissor which ignores the painter matrix,
1490
+ // so track the frame in screen space: ancestor zooms are accumulated
1491
+ // in 'scale' and ancestor positions in 'offset'
1492
+ clip &= Bounds(
1493
+ bounds.x * scale + offset.x, bounds.y * scale + offset.y,
1494
+ bounds.w * scale, bounds.h * scale);
1495
+ }
1305
1496
 
1497
+ Point pos = bounds.position();
1306
1498
  bounds.set_position(0, 0, bounds.z);
1307
1499
  if (self->pscroll)
1308
1500
  {
@@ -1320,6 +1512,10 @@ namespace Reflex
1320
1512
  if (pivot) p->translate( pivot->x * bounds.w, pivot->y * bounds.h);
1321
1513
  p->rotate(self->angle);
1322
1514
  if (pivot) p->translate(-pivot->x * bounds.w, -pivot->y * bounds.h);
1515
+
1516
+ // a rotated frame can not be represented as a screen-space
1517
+ // scissor rect, so give up clipping from here on down
1518
+ clip.reset(-1);
1323
1519
  }
1324
1520
 
1325
1521
  float zoom = self->zoom;
@@ -1332,8 +1528,9 @@ namespace Reflex
1332
1528
 
1333
1529
  if (!draw_view_with_cache(view, &e, redraw))
1334
1530
  {
1335
- pos += offset;
1336
- draw_view(view, &e, pos, clip2);
1531
+ draw_view(
1532
+ view, &e, Point(pos.x * scale + offset.x, pos.y * scale + offset.y),
1533
+ clip, zoom > 0 ? scale * zoom : scale);
1337
1534
  }
1338
1535
 
1339
1536
  p->pop_matrix();
@@ -1362,6 +1559,26 @@ namespace Reflex
1362
1559
  view->self->add_flag(View::Data::UPDATE_SHAPES);
1363
1560
  }
1364
1561
 
1562
+ void
1563
+ View_get_hovered_views (ViewList* result, View* view, const Point& position)
1564
+ {
1565
+ if (!result)
1566
+ argument_error(__FILE__, __LINE__);
1567
+ if (!view)
1568
+ argument_error(__FILE__, __LINE__);
1569
+
1570
+ if (view->hidden() || !view->frame().is_include(position))
1571
+ return;
1572
+
1573
+ result->emplace_back(view);
1574
+
1575
+ Point pos = view->from_parent(position);
1576
+ call_children(view, [&](View* child) {
1577
+ View_get_hovered_views(result, child, pos);
1578
+ return true;
1579
+ });
1580
+ }
1581
+
1365
1582
  void
1366
1583
  View_call_key_event (View* view, KeyEvent* event)
1367
1584
  {
@@ -1384,16 +1601,23 @@ namespace Reflex
1384
1601
  }
1385
1602
  }
1386
1603
 
1387
- static void
1388
- call_children (View* parent, std::function<bool(View*)> fun, bool sort = true)
1604
+ void
1605
+ View_call_text_event (View* view, TextEvent* event)
1389
1606
  {
1390
- auto* children = parent->self->children(false, sort);
1391
- if (!children) return;
1607
+ if (!view)
1608
+ argument_error(__FILE__, __LINE__);
1609
+ if (!event)
1610
+ argument_error(__FILE__, __LINE__);
1392
1611
 
1393
- for (auto it = children->rbegin(), end = children->rend(); it != end; ++it)
1612
+ TextEvent e = event->dup();
1613
+ view->on_text(&e);
1614
+ if (e.is_blocked()) return;
1615
+
1616
+ switch (e.action())
1394
1617
  {
1395
- if (!fun(it->get()))
1396
- break;
1618
+ case TextEvent::PREEDIT: view->on_text_preedit(&e); break;
1619
+ case TextEvent::COMMIT: view->on_text_commit(&e); break;
1620
+ default: break;
1397
1621
  }
1398
1622
  }
1399
1623
 
@@ -1414,8 +1638,17 @@ namespace Reflex
1414
1638
  if (view->self->pbody)
1415
1639
  view->self->pbody->awake();
1416
1640
 
1641
+ Window* win = view->window();
1642
+ uint cancels = Window_get_pointer_cancels(*win);
1643
+ auto block_if_canceled = [&]()
1644
+ {
1645
+ if (Window_get_pointer_cancels(*win) != cancels)
1646
+ event->block();
1647
+ return event->is_blocked();
1648
+ };
1649
+
1417
1650
  view->on_pointer(event);
1418
- if (event->is_blocked()) return;
1651
+ if (block_if_canceled()) return;
1419
1652
 
1420
1653
  switch ((*event)[0].action())
1421
1654
  {
@@ -1423,8 +1656,12 @@ namespace Reflex
1423
1656
  case Pointer::UP: view->on_pointer_up(event); break;
1424
1657
  case Pointer::MOVE: view->on_pointer_move(event); break;
1425
1658
  case Pointer::CANCEL: view->on_pointer_cancel(event); break;
1659
+ case Pointer::ENTER: view->on_pointer_enter(event); break;
1660
+ case Pointer::LEAVE: view->on_pointer_leave(event); break;
1426
1661
  default: break;
1427
1662
  }
1663
+
1664
+ block_if_canceled();
1428
1665
  }
1429
1666
 
1430
1667
  static void
@@ -1460,7 +1697,7 @@ namespace Reflex
1460
1697
  if (!event)
1461
1698
  argument_error(__FILE__, __LINE__);
1462
1699
 
1463
- if (view->hidden() || event->empty())
1700
+ if (event->empty() || view->hidden())
1464
1701
  return;
1465
1702
 
1466
1703
  Window* win = view->window();
@@ -1469,6 +1706,10 @@ namespace Reflex
1469
1706
 
1470
1707
  PointerEvent e = event->dup();
1471
1708
 
1709
+ auto action = e[0].action();
1710
+ if (action == Pointer::ENTER || action == Pointer::LEAVE)
1711
+ return call_pointer_events(view, &e);
1712
+
1472
1713
  if (!e.is_captured())
1473
1714
  call_pointer_events_for_each_child(view, &e);
1474
1715
 
@@ -1509,6 +1750,25 @@ namespace Reflex
1509
1750
  view->on_wheel(&e);
1510
1751
  }
1511
1752
 
1753
+ void
1754
+ View_call_contact_event (View* view, ContactEvent* event)
1755
+ {
1756
+ if (!view)
1757
+ argument_error(__FILE__, __LINE__);
1758
+ if (!event)
1759
+ argument_error(__FILE__, __LINE__);
1760
+
1761
+ ContactEvent e = event->dup();
1762
+ view->on_contact(&e);
1763
+
1764
+ switch (e.action())
1765
+ {
1766
+ case ContactEvent::BEGIN: view->on_contact_begin(&e); break;
1767
+ case ContactEvent::END: view->on_contact_end(&e); break;
1768
+ default: break;
1769
+ }
1770
+ }
1771
+
1512
1772
  void
1513
1773
  View_call_midi_event (View* view, MIDIEvent* event)
1514
1774
  {
@@ -1559,25 +1819,6 @@ namespace Reflex
1559
1819
  view->on_control_change(&e);
1560
1820
  }
1561
1821
 
1562
- void
1563
- View_call_contact_event (View* view, ContactEvent* event)
1564
- {
1565
- if (!view)
1566
- argument_error(__FILE__, __LINE__);
1567
- if (!event)
1568
- argument_error(__FILE__, __LINE__);
1569
-
1570
- ContactEvent e = event->dup();
1571
- view->on_contact(&e);
1572
-
1573
- switch (e.action())
1574
- {
1575
- case ContactEvent::BEGIN: view->on_contact_begin(&e); break;
1576
- case ContactEvent::END: view->on_contact_end(&e); break;
1577
- default: break;
1578
- }
1579
- }
1580
-
1581
1822
 
1582
1823
  View::View (const char* name)
1583
1824
  {
@@ -1586,6 +1827,8 @@ namespace Reflex
1586
1827
 
1587
1828
  View::~View ()
1588
1829
  {
1830
+ self->sever_constraints();
1831
+
1589
1832
  clear_children();// to delete child shapes before world.
1590
1833
  }
1591
1834
 
@@ -1636,13 +1879,14 @@ namespace Reflex
1636
1879
  void
1637
1880
  View::redraw ()
1638
1881
  {
1639
- if (self->has_flag(Data::REDRAW))
1882
+ View* parent = self->parent;
1883
+ if (self->has_flag(Data::REDRAW) && (!parent || parent->self->has_flag(Data::REDRAW)))
1640
1884
  return;
1641
1885
 
1642
1886
  self->add_flag(Data::REDRAW);
1643
1887
 
1644
- if (self->parent)
1645
- self->parent->redraw();
1888
+ if (parent)
1889
+ parent->redraw();
1646
1890
  else if (self->window)
1647
1891
  self->window->redraw();
1648
1892
  }
@@ -1691,6 +1935,39 @@ namespace Reflex
1691
1935
  redraw();
1692
1936
  }
1693
1937
 
1938
+ void
1939
+ View::fit_to_content ()
1940
+ {
1941
+ self->add_flag(View::Data::FIT_TO_CONTENT);
1942
+ }
1943
+
1944
+ Bounds
1945
+ View::content_bounds () const
1946
+ {
1947
+ Bounds bounds = Rays::invalid_bounds();
1948
+ self->each_shape([&](const Shape* shape)
1949
+ {
1950
+ if (!shape || !Shape_has_frame(*shape))
1951
+ return;
1952
+
1953
+ Bounds frame = shape->frame();
1954
+ if (frame) bounds |= frame;
1955
+ });
1956
+ return bounds;
1957
+ }
1958
+
1959
+ bool
1960
+ View::accepts_text_input () const
1961
+ {
1962
+ return !hidden() && self->has_flag(FLAG_TEXT_INPUT);
1963
+ }
1964
+
1965
+ Bounds
1966
+ View::text_input_bounds () const
1967
+ {
1968
+ return frame().dup().move_to(0, 0);
1969
+ }
1970
+
1694
1971
  static void
1695
1972
  get_from_parent_matrix (Matrix* m, const View* view)
1696
1973
  {
@@ -1823,21 +2100,30 @@ namespace Reflex
1823
2100
  assert(it != end);
1824
2101
 
1825
2102
  children->erase(it);
1826
- if (children->empty())
2103
+
2104
+ View::ChildList* children_for_loop = parent->self->pchildren_for_loop.get();
2105
+ if (children_for_loop)
1827
2106
  {
1828
- parent->self->pchildren.reset();
1829
- parent->self->pchildren_sorted.reset();
2107
+ auto loop_end = children_for_loop->end();
2108
+ auto loop_it = std::find(children_for_loop->begin(), loop_end, child);
2109
+ if (loop_it != loop_end) loop_it->reset();
1830
2110
  }
2111
+
2112
+ if (children->empty())
2113
+ parent->self->pchildren.reset();
1831
2114
  }
1832
2115
 
1833
2116
  void
1834
- View::add_child (View* child)
2117
+ View::add_child (View* child, int index)
1835
2118
  {
1836
2119
  if (!child)
1837
2120
  argument_error(__FILE__, __LINE__);
1838
2121
  if (child == this)
1839
2122
  argument_error(__FILE__, __LINE__);
1840
2123
 
2124
+ if (World_is_stepping(self->pchild_world.get()))
2125
+ physics_error(__FILE__, __LINE__, "world is stepping now");
2126
+
1841
2127
  bool found = std::find(child_begin(), child_end(), child) != child_end();
1842
2128
  bool belong = child->parent() == this;
1843
2129
  if (found && belong)
@@ -1845,14 +2131,16 @@ namespace Reflex
1845
2131
  else if (found != belong)
1846
2132
  invalid_state_error(__FILE__, __LINE__);
1847
2133
 
1848
- self->children(true)->push_back(child);
2134
+ auto* children = self->children(true);
2135
+ if (index < 0 || (int) children->size() < index)
2136
+ children->push_back(child);
2137
+ else
2138
+ children->insert(children->begin() + (size_t) index, child);
1849
2139
 
1850
2140
  View* prev_parent = child->parent();
1851
2141
  set_parent(child, this);
1852
-
1853
2142
  if (prev_parent)
1854
2143
  erase_child_from_children(prev_parent, child);
1855
-
1856
2144
  self->sort_children();
1857
2145
 
1858
2146
  update_view_layout(this);
@@ -1866,6 +2154,9 @@ namespace Reflex
1866
2154
  if (child == this)
1867
2155
  argument_error(__FILE__, __LINE__);
1868
2156
 
2157
+ if (World_is_stepping(self->pchild_world.get()))
2158
+ physics_error(__FILE__, __LINE__, "world is stepping now");
2159
+
1869
2160
  bool found = std::find(child_begin(), child_end(), child) != child_end();
1870
2161
  bool belong = child->parent() == this;
1871
2162
  if (!found && !belong)
@@ -1873,19 +2164,11 @@ namespace Reflex
1873
2164
  else if (found != belong)
1874
2165
  invalid_state_error(__FILE__, __LINE__);
1875
2166
 
1876
- if (self->has_flag(Data::UPDATING))
1877
- {
1878
- // delay removing child to avoid breaking child list looped on View_update_tree()
1879
- self->add_flag(Data::HAS_CHILDREN_TO_REMOVE);
1880
- child->self->add_flag(Data::REMOVE_FROM_PARENT);
1881
- }
1882
- else
1883
- {
1884
- set_parent(child, NULL);
1885
- erase_child_from_children(this, child);
1886
- self->sort_children();
1887
- update_view_layout(this);
1888
- }
2167
+ set_parent(child, NULL);
2168
+ erase_child_from_children(this, child);
2169
+ self->sort_children();
2170
+
2171
+ update_view_layout(this);
1889
2172
  }
1890
2173
 
1891
2174
  void
@@ -2060,10 +2343,7 @@ namespace Reflex
2060
2343
  void
2061
2344
  View::set_shape (Shape* shape)
2062
2345
  {
2063
- if (!shape)
2064
- self->add_flag(Data::NO_SHAPE);
2065
- else
2066
- self->remove_flag(Data::NO_SHAPE);
2346
+ self->update_flag(Data::NO_SHAPE, !shape);
2067
2347
 
2068
2348
  Shape::Ref& pshape = self->pshape;
2069
2349
  if (shape == pshape.get()) return;
@@ -2089,12 +2369,17 @@ namespace Reflex
2089
2369
  }
2090
2370
 
2091
2371
  void
2092
- View::add_shape (Shape* shape)
2372
+ View::add_shape (Shape* shape, int index)
2093
2373
  {
2094
2374
  if (!shape) return;
2095
2375
 
2096
2376
  Shape_set_owner(shape, this);
2097
- self->shapes().push_back(shape);
2377
+
2378
+ auto& shapes = self->shapes();
2379
+ if (index < 0 || (int) shapes.size() < index)
2380
+ shapes.push_back(shape);
2381
+ else
2382
+ shapes.insert(shapes.begin() + (size_t) index, shape);
2098
2383
  }
2099
2384
 
2100
2385
  void
@@ -2131,7 +2416,7 @@ namespace Reflex
2131
2416
  {
2132
2417
  for (auto& shape : *pshapes)
2133
2418
  {
2134
- if (selector.contains(shape->selector()))
2419
+ if (shape->selector().contains(selector))
2135
2420
  result.push_back(shape);
2136
2421
  }
2137
2422
  }
@@ -2168,6 +2453,58 @@ namespace Reflex
2168
2453
  return self->pshapes->end();
2169
2454
  }
2170
2455
 
2456
+ void
2457
+ View::clear_constraints ()
2458
+ {
2459
+ self->sever_constraints();
2460
+ }
2461
+
2462
+ View::ConstraintList
2463
+ View::find_constraints (const Selector& selector) const
2464
+ {
2465
+ ConstraintList result;
2466
+ ConstraintList* pconstraints = self->pconstraints.get();
2467
+ if (pconstraints)
2468
+ {
2469
+ for (auto& constraint : *pconstraints)
2470
+ {
2471
+ if (constraint->selector().contains(selector))
2472
+ result.push_back(constraint);
2473
+ }
2474
+ }
2475
+ return result;
2476
+ }
2477
+
2478
+ static View::ConstraintList empty_constraints;
2479
+
2480
+ View::constraint_iterator
2481
+ View::constraint_begin ()
2482
+ {
2483
+ if (!self->pconstraints) return empty_constraints.begin();
2484
+ return self->pconstraints->begin();
2485
+ }
2486
+
2487
+ View::const_constraint_iterator
2488
+ View::constraint_begin () const
2489
+ {
2490
+ if (!self->pconstraints) return empty_constraints.begin();
2491
+ return self->pconstraints->begin();
2492
+ }
2493
+
2494
+ View::constraint_iterator
2495
+ View::constraint_end ()
2496
+ {
2497
+ if (!self->pconstraints) return empty_constraints.end();
2498
+ return self->pconstraints->end();
2499
+ }
2500
+
2501
+ View::const_constraint_iterator
2502
+ View::constraint_end () const
2503
+ {
2504
+ if (!self->pconstraints) return empty_constraints.end();
2505
+ return self->pconstraints->end();
2506
+ }
2507
+
2171
2508
  void
2172
2509
  View::set_filter (Filter* filter)
2173
2510
  {
@@ -2259,27 +2596,6 @@ namespace Reflex
2259
2596
  return self->frame;
2260
2597
  }
2261
2598
 
2262
- Bounds
2263
- View::content_bounds () const
2264
- {
2265
- Bounds bounds = Rays::invalid_bounds();
2266
- self->each_shape([&](const Shape* shape)
2267
- {
2268
- if (!shape || !Shape_has_frame(*shape))
2269
- return;
2270
-
2271
- Bounds frame = shape->frame();
2272
- if (frame) bounds |= frame;
2273
- });
2274
- return bounds;
2275
- }
2276
-
2277
- void
2278
- View::fit_to_content ()
2279
- {
2280
- self->add_flag(View::Data::FIT_TO_CONTENT);
2281
- }
2282
-
2283
2599
  void
2284
2600
  View::set_zoom (float zoom)
2285
2601
  {
@@ -2626,10 +2942,9 @@ namespace Reflex
2626
2942
  }
2627
2943
 
2628
2944
  void
2629
- View::update_world (float duration)
2945
+ View::update_world ()
2630
2946
  {
2631
- World* w = self->pchild_world.get();
2632
- if (w) w->update(duration);
2947
+ update_child_world(this);
2633
2948
  }
2634
2949
 
2635
2950
  float
@@ -2736,6 +3051,16 @@ namespace Reflex
2736
3051
  {
2737
3052
  }
2738
3053
 
3054
+ void
3055
+ View::on_activate (Event* e)
3056
+ {
3057
+ }
3058
+
3059
+ void
3060
+ View::on_deactivate (Event* e)
3061
+ {
3062
+ }
3063
+
2739
3064
  void
2740
3065
  View::on_show (Event* e)
2741
3066
  {
@@ -2802,59 +3127,59 @@ namespace Reflex
2802
3127
  }
2803
3128
 
2804
3129
  void
2805
- View::on_pointer (PointerEvent* e)
3130
+ View::on_text (TextEvent* e)
2806
3131
  {
2807
3132
  }
2808
3133
 
2809
3134
  void
2810
- View::on_pointer_down (PointerEvent* e)
3135
+ View::on_text_preedit (TextEvent* e)
2811
3136
  {
2812
3137
  }
2813
3138
 
2814
3139
  void
2815
- View::on_pointer_up (PointerEvent* e)
3140
+ View::on_text_commit (TextEvent* e)
2816
3141
  {
2817
3142
  }
2818
3143
 
2819
3144
  void
2820
- View::on_pointer_move (PointerEvent* e)
3145
+ View::on_pointer (PointerEvent* e)
2821
3146
  {
2822
3147
  }
2823
3148
 
2824
3149
  void
2825
- View::on_pointer_cancel (PointerEvent* e)
3150
+ View::on_pointer_down (PointerEvent* e)
2826
3151
  {
2827
3152
  }
2828
3153
 
2829
3154
  void
2830
- View::on_wheel (WheelEvent* e)
3155
+ View::on_pointer_up (PointerEvent* e)
2831
3156
  {
2832
- //scroll_by(e->dx, e->dy, e->dz);
2833
3157
  }
2834
3158
 
2835
3159
  void
2836
- View::on_midi (MIDIEvent* e)
3160
+ View::on_pointer_move (PointerEvent* e)
2837
3161
  {
2838
3162
  }
2839
3163
 
2840
3164
  void
2841
- View::on_note (NoteEvent* e)
3165
+ View::on_pointer_cancel (PointerEvent* e)
2842
3166
  {
2843
3167
  }
2844
3168
 
2845
3169
  void
2846
- View::on_note_on (NoteEvent* e)
3170
+ View::on_pointer_enter (PointerEvent* e)
2847
3171
  {
2848
3172
  }
2849
3173
 
2850
3174
  void
2851
- View::on_note_off (NoteEvent* e)
3175
+ View::on_pointer_leave (PointerEvent* e)
2852
3176
  {
2853
3177
  }
2854
3178
 
2855
3179
  void
2856
- View::on_control_change (ControlChangeEvent* e)
3180
+ View::on_wheel (WheelEvent* e)
2857
3181
  {
3182
+ //scroll_by(e->dx, e->dy, e->dz);
2858
3183
  }
2859
3184
 
2860
3185
  void
@@ -2888,6 +3213,31 @@ namespace Reflex
2888
3213
  {
2889
3214
  }
2890
3215
 
3216
+ void
3217
+ View::on_midi (MIDIEvent* e)
3218
+ {
3219
+ }
3220
+
3221
+ void
3222
+ View::on_note (NoteEvent* e)
3223
+ {
3224
+ }
3225
+
3226
+ void
3227
+ View::on_note_on (NoteEvent* e)
3228
+ {
3229
+ }
3230
+
3231
+ void
3232
+ View::on_note_off (NoteEvent* e)
3233
+ {
3234
+ }
3235
+
3236
+ void
3237
+ View::on_control_change (ControlChangeEvent* e)
3238
+ {
3239
+ }
3240
+
2891
3241
  View::operator bool () const
2892
3242
  {
2893
3243
  return true;