reflexion 0.6.0 → 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 (275) hide show
  1. checksums.yaml +4 -4
  2. data/.doc/ext/reflex/application.cpp +37 -6
  3. data/.doc/ext/reflex/capture_event.cpp +1 -1
  4. data/.doc/ext/reflex/chase_constraint.cpp +1 -1
  5. data/.doc/ext/reflex/clipboard.cpp +1 -1
  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 +1 -1
  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 +1 -1
  26. data/.doc/ext/reflex/menu.cpp +6 -5
  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 +18 -6
  31. data/.doc/ext/reflex/note_event.cpp +1 -1
  32. data/.doc/ext/reflex/pin.cpp +1 -1
  33. data/.doc/ext/reflex/pointer.cpp +1 -1
  34. data/.doc/ext/reflex/pointer_event.cpp +2 -2
  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 +566 -232
  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 +1 -1
  41. data/.doc/ext/reflex/shape.cpp +1 -1
  42. data/.doc/ext/reflex/snap_constraint.cpp +1 -1
  43. data/.doc/ext/reflex/style.cpp +1 -1
  44. data/.doc/ext/reflex/style_length.cpp +1 -1
  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 +110 -56
  50. data/.doc/ext/reflex/wheel_constraint.cpp +1 -1
  51. data/.doc/ext/reflex/wheel_event.cpp +1 -1
  52. data/.doc/ext/reflex/window.cpp +226 -17
  53. data/.github/workflows/release-gem.yml +2 -49
  54. data/.github/workflows/tag.yml +5 -28
  55. data/.github/workflows/test.yml +1 -37
  56. data/ChangeLog.md +54 -0
  57. data/Gemfile.lock +13 -8
  58. data/Rakefile +13 -2
  59. data/Reflex.podspec +2 -2
  60. data/VERSION +1 -1
  61. data/ext/reflex/application.cpp +41 -6
  62. data/ext/reflex/capture_event.cpp +1 -1
  63. data/ext/reflex/chase_constraint.cpp +1 -1
  64. data/ext/reflex/clipboard.cpp +1 -1
  65. data/ext/reflex/color_event.cpp +80 -0
  66. data/ext/reflex/color_picker.cpp +121 -0
  67. data/ext/reflex/constraint.cpp +1 -1
  68. data/ext/reflex/contact_event.cpp +1 -1
  69. data/ext/reflex/control_change_event.cpp +1 -1
  70. data/ext/reflex/device.cpp +1 -1
  71. data/ext/reflex/device_event.cpp +1 -1
  72. data/ext/reflex/draw_event.cpp +1 -1
  73. data/ext/reflex/ellipse_shape.cpp +1 -1
  74. data/ext/reflex/event.cpp +1 -1
  75. data/ext/reflex/extconf.rb +4 -2
  76. data/ext/reflex/file_dialog.cpp +194 -0
  77. data/ext/reflex/file_event.cpp +108 -0
  78. data/ext/reflex/filter.cpp +1 -1
  79. data/ext/reflex/focus_event.cpp +1 -1
  80. data/ext/reflex/frame_event.cpp +1 -1
  81. data/ext/reflex/gamepad.cpp +50 -0
  82. data/ext/reflex/image_view.cpp +1 -1
  83. data/ext/reflex/key_event.cpp +1 -275
  84. data/ext/reflex/line_shape.cpp +1 -1
  85. data/ext/reflex/link_constraint.cpp +1 -1
  86. data/ext/reflex/menu.cpp +8 -7
  87. data/ext/reflex/midi.cpp +11 -3
  88. data/ext/reflex/midi_event.cpp +1 -1
  89. data/ext/reflex/motion_event.cpp +1 -1
  90. data/ext/reflex/native.cpp +18 -6
  91. data/ext/reflex/note_event.cpp +1 -1
  92. data/ext/reflex/pin.cpp +1 -1
  93. data/ext/reflex/pointer.cpp +1 -1
  94. data/ext/reflex/pointer_event.cpp +2 -2
  95. data/ext/reflex/polygon_shape.cpp +1 -1
  96. data/ext/reflex/rect_shape.cpp +1 -1
  97. data/ext/reflex/reflex.cpp +568 -232
  98. data/ext/reflex/screen.cpp +31 -2
  99. data/ext/reflex/scroll_event.cpp +1 -1
  100. data/ext/reflex/selector.cpp +1 -1
  101. data/ext/reflex/selector.h +9 -9
  102. data/ext/reflex/shape.cpp +1 -1
  103. data/ext/reflex/snap_constraint.cpp +1 -1
  104. data/ext/reflex/style.cpp +1 -1
  105. data/ext/reflex/style_length.cpp +1 -1
  106. data/ext/reflex/text_event.cpp +111 -0
  107. data/ext/reflex/timer.cpp +1 -1
  108. data/ext/reflex/timer_event.cpp +1 -1
  109. data/ext/reflex/update_event.cpp +1 -1
  110. data/ext/reflex/view.cpp +121 -61
  111. data/ext/reflex/wheel_constraint.cpp +1 -1
  112. data/ext/reflex/wheel_event.cpp +1 -1
  113. data/ext/reflex/window.cpp +256 -25
  114. data/include/reflex/application.h +10 -0
  115. data/include/reflex/color_picker.h +65 -0
  116. data/include/reflex/event.h +178 -88
  117. data/include/reflex/file_dialog.h +73 -0
  118. data/include/reflex/gamepad.h +3 -0
  119. data/include/reflex/menu.h +3 -3
  120. data/include/reflex/midi.h +3 -0
  121. data/include/reflex/reflex.h +2 -0
  122. data/include/reflex/ruby/application.h +6 -1
  123. data/include/reflex/ruby/color_picker.h +89 -0
  124. data/include/reflex/ruby/event.h +62 -29
  125. data/include/reflex/ruby/file_dialog.h +89 -0
  126. data/include/reflex/ruby/gamepad.h +46 -0
  127. data/include/reflex/ruby/reflex.h +3 -0
  128. data/include/reflex/ruby/view.h +92 -44
  129. data/include/reflex/ruby/window.h +60 -1
  130. data/include/reflex/ruby.h +3 -0
  131. data/include/reflex/screen.h +11 -2
  132. data/include/reflex/view.h +28 -16
  133. data/include/reflex/window.h +40 -8
  134. data/include/reflex.h +3 -0
  135. data/lib/reflex/application.rb +5 -5
  136. data/lib/reflex/autoinit.rb +3 -1
  137. data/lib/reflex/button.rb +3 -3
  138. data/lib/reflex/color_event.rb +16 -0
  139. data/lib/reflex/color_picker.rb +45 -0
  140. data/lib/reflex/control_change_event.rb +17 -0
  141. data/lib/reflex/file_dialog.rb +70 -0
  142. data/lib/reflex/file_event.rb +37 -0
  143. data/lib/reflex/helper.rb +58 -7
  144. data/lib/reflex/key_event.rb +9 -4
  145. data/lib/reflex/menu.rb +17 -1
  146. data/lib/reflex/model.rb +19 -19
  147. data/lib/reflex/note_event.rb +1 -1
  148. data/lib/reflex/pointer.rb +14 -3
  149. data/lib/reflex/pointer_event.rb +12 -1
  150. data/lib/reflex/reflex.rb +5 -0
  151. data/lib/reflex/shape.rb +14 -14
  152. data/lib/reflex/style.rb +16 -16
  153. data/lib/reflex/text_event.rb +40 -0
  154. data/lib/reflex/timer.rb +3 -3
  155. data/lib/reflex/view.rb +29 -14
  156. data/lib/reflex/wheel_event.rb +12 -3
  157. data/lib/reflex/window.rb +25 -13
  158. data/lib/reflex.rb +8 -2
  159. data/reflex.gemspec +4 -4
  160. data/samples/ime.rb +100 -0
  161. data/samples/ios/hello/hello.xcodeproj/project.pbxproj +236 -224
  162. data/samples/menu.rb +4 -1
  163. data/samples/model.rb +3 -3
  164. data/samples/test/alert.rb +93 -0
  165. data/samples/test/always_on.rb +76 -0
  166. data/samples/test/app_background.rb +51 -0
  167. data/samples/test/boundary.rb +75 -0
  168. data/samples/test/callback_exception.rb +101 -0
  169. data/samples/test/cancel.rb +53 -0
  170. data/samples/test/color_picker.rb +63 -0
  171. data/samples/test/file_dialog.rb +102 -0
  172. data/samples/window_style.rb +156 -0
  173. data/src/application.cpp +159 -18
  174. data/src/application.h +92 -7
  175. data/src/color_picker.cpp +113 -0
  176. data/src/color_picker.h +36 -0
  177. data/src/event.cpp +410 -252
  178. data/src/event.h +12 -0
  179. data/src/file_dialog.cpp +163 -0
  180. data/src/file_dialog.h +52 -0
  181. data/src/gamepad.cpp +42 -5
  182. data/src/gamepad.h +4 -0
  183. data/src/ios/app_delegate.mm +5 -3
  184. data/src/ios/application.mm +24 -0
  185. data/src/ios/color_picker.mm +19 -0
  186. data/src/ios/file_dialog.mm +21 -0
  187. data/src/ios/gamepad.mm +4 -4
  188. data/src/ios/menu.mm +5 -0
  189. data/src/ios/reflex.mm +8 -0
  190. data/src/ios/screen.mm +26 -0
  191. data/src/ios/view_controller.mm +2 -30
  192. data/src/ios/window.mm +38 -9
  193. data/src/menu.cpp +66 -4
  194. data/src/menu.h +17 -1
  195. data/src/midi.cpp +61 -31
  196. data/src/osx/app_delegate.h +4 -0
  197. data/src/osx/app_delegate.mm +102 -22
  198. data/src/osx/application.mm +88 -6
  199. data/src/osx/color_picker.mm +112 -0
  200. data/src/osx/event.h +10 -0
  201. data/src/osx/event.mm +84 -30
  202. data/src/osx/file_dialog.mm +168 -0
  203. data/src/osx/gamepad.mm +2 -2
  204. data/src/osx/gamepad_hid.mm +1 -1
  205. data/src/osx/menu.mm +177 -33
  206. data/src/osx/native_window.h +16 -2
  207. data/src/osx/native_window.mm +114 -57
  208. data/src/osx/opengl_view.h +2 -1
  209. data/src/osx/opengl_view.mm +184 -43
  210. data/src/osx/reflex.mm +38 -0
  211. data/src/osx/screen.mm +36 -0
  212. data/src/osx/window.mm +106 -24
  213. data/src/pointer.cpp +13 -4
  214. data/src/pointer.h +4 -0
  215. data/src/rays.h +46 -0
  216. data/src/sdl/application.cpp +68 -8
  217. data/src/sdl/color_picker.cpp +18 -0
  218. data/src/sdl/event.cpp +24 -3
  219. data/src/sdl/event.h +12 -0
  220. data/src/sdl/file_dialog.cpp +20 -0
  221. data/src/sdl/gamepad.cpp +3 -7
  222. data/src/sdl/menu.cpp +5 -0
  223. data/src/sdl/reflex.cpp +20 -0
  224. data/src/sdl/screen.cpp +36 -0
  225. data/src/sdl/window.cpp +142 -29
  226. data/src/shape.cpp +15 -10
  227. data/src/view.cpp +287 -198
  228. data/src/view.h +4 -2
  229. data/src/vk.h +416 -0
  230. data/src/win32/application.cpp +162 -12
  231. data/src/win32/application.h +20 -0
  232. data/src/win32/color_picker.cpp +82 -0
  233. data/src/win32/event.cpp +114 -12
  234. data/src/win32/event.h +21 -4
  235. data/src/win32/file_dialog.cpp +226 -0
  236. data/src/win32/gamepad.cpp +9 -2
  237. data/src/win32/menu.cpp +191 -53
  238. data/src/win32/menu.h +9 -1
  239. data/src/win32/opengl.cpp +2 -9
  240. data/src/win32/reflex.cpp +44 -3
  241. data/src/win32/screen.cpp +164 -3
  242. data/src/win32/screen.h +8 -0
  243. data/src/win32/tray.cpp +191 -0
  244. data/src/win32/tray.h +22 -0
  245. data/src/win32/vk.cpp +11 -0
  246. data/src/win32/window.cpp +809 -148
  247. data/src/win32/window.h +6 -0
  248. data/src/window.cpp +718 -185
  249. data/src/window.h +66 -33
  250. data/src/world.cpp +9 -1
  251. data/test/helper.rb +17 -0
  252. data/test/test_application.rb +90 -1
  253. data/test/test_chase_constraint.rb +1 -3
  254. data/test/test_color_event.rb +36 -0
  255. data/test/test_color_picker.rb +62 -0
  256. data/test/test_constraint.rb +2 -4
  257. data/test/test_event.rb +1 -1
  258. data/test/test_file_dialog.rb +48 -0
  259. data/test/test_file_event.rb +43 -0
  260. data/test/test_has_text_preedit.rb +54 -0
  261. data/test/test_key_event.rb +20 -5
  262. data/test/test_link_constraint.rb +1 -3
  263. data/test/test_menu.rb +40 -10
  264. data/test/test_pointer.rb +33 -23
  265. data/test/test_pointer_event.rb +24 -9
  266. data/test/test_reflex.rb +36 -0
  267. data/test/test_screen.rb +24 -2
  268. data/test/test_snap_constraint.rb +1 -3
  269. data/test/test_text_event.rb +54 -0
  270. data/test/test_view.rb +41 -4
  271. data/test/test_wheel_constraint.rb +1 -3
  272. data/test/test_wheel_event.rb +13 -5
  273. data/test/test_window.rb +196 -44
  274. metadata +80 -10
  275. 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>
@@ -40,29 +41,23 @@ namespace Reflex
40
41
  enum Flag
41
42
  {
42
43
 
43
- UPDATING = Xot::bit(1, FLAG_LAST),
44
+ NO_SHAPE = Xot::bit(1, FLAG_LAST),
44
45
 
45
- NO_SHAPE = Xot::bit(2, FLAG_LAST),
46
+ HAS_VARIABLE_LENGTHS = Xot::bit(2, FLAG_LAST),
46
47
 
47
- HAS_VARIABLE_LENGTHS = Xot::bit(3, FLAG_LAST),
48
+ REDRAW = Xot::bit(3, FLAG_LAST),
48
49
 
49
- HAS_CHILDREN_TO_REMOVE = Xot::bit(4, FLAG_LAST),
50
+ APPLY_STYLE = Xot::bit(4, FLAG_LAST),
50
51
 
51
- REMOVE_FROM_PARENT = Xot::bit(5, FLAG_LAST),
52
+ UPDATE_STYLE = Xot::bit(5, FLAG_LAST),
52
53
 
53
- REDRAW = Xot::bit(6, FLAG_LAST),
54
+ UPDATE_SHAPES = Xot::bit(6, FLAG_LAST),
54
55
 
55
- APPLY_STYLE = Xot::bit(7, FLAG_LAST),
56
+ UPDATE_LAYOUT = Xot::bit(7, FLAG_LAST),
56
57
 
57
- UPDATE_STYLE = Xot::bit(8, FLAG_LAST),
58
+ SORT_CHILDREN = Xot::bit(8, FLAG_LAST),
58
59
 
59
- UPDATE_SHAPES = Xot::bit(9, FLAG_LAST),
60
-
61
- UPDATE_LAYOUT = Xot::bit(10, FLAG_LAST),
62
-
63
- SORT_CHILDREN = Xot::bit(11, FLAG_LAST),
64
-
65
- FIT_TO_CONTENT = Xot::bit(12, FLAG_LAST),
60
+ FIT_TO_CONTENT = Xot::bit(9, FLAG_LAST),
66
61
 
67
62
  };// Flag
68
63
 
@@ -82,6 +77,8 @@ namespace Reflex
82
77
 
83
78
  ushort child_index = 0;
84
79
 
80
+ int loop_depth = 0;
81
+
85
82
  uint flags =
86
83
  FLAG_CLIP | FLAG_RESIZE_TO_FIT | REDRAW | UPDATE_LAYOUT | UPDATE_STYLE;
87
84
 
@@ -93,7 +90,7 @@ namespace Reflex
93
90
 
94
91
  std::unique_ptr<SelectorSet> pselectors_for_update;
95
92
 
96
- std::unique_ptr<Image> pcache_image;
93
+ std::unique_ptr<Image> pdraw_cache;
97
94
 
98
95
  std::unique_ptr<Timers> ptimers;
99
96
 
@@ -115,7 +112,7 @@ namespace Reflex
115
112
 
116
113
  std::unique_ptr<ChildList> pchildren;
117
114
 
118
- std::unique_ptr<ChildList> pchildren_sorted;
115
+ std::unique_ptr<ChildList> pchildren_for_loop;
119
116
 
120
117
  Point& pivot ()
121
118
  {
@@ -364,24 +361,30 @@ namespace Reflex
364
361
  view->remove_child(wall.get());
365
362
  }
366
363
 
367
- ChildList* children (bool create = false, bool sort = false)
364
+ ChildList* children (bool create = false)
368
365
  {
369
- if (!pchildren)
370
- {
371
- if (!create) return NULL;
372
- pchildren.reset(new ChildList);
373
- }
374
-
375
- if (sort && check_and_remove_flag(SORT_CHILDREN))
376
- do_sort_children();
366
+ if (!pchildren && create) pchildren.reset(new ChildList);
367
+ return pchildren.get();
368
+ }
377
369
 
378
- 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();
379
374
  }
380
375
 
381
- void sort_children (bool order_only = false)
376
+ void sort_children ()
382
377
  {
383
378
  add_flag(SORT_CHILDREN);
384
- 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();
385
388
  }
386
389
 
387
390
  void add_flag (uint flag)
@@ -394,6 +397,11 @@ namespace Reflex
394
397
  Xot::remove_flag(&flags, flag);
395
398
  }
396
399
 
400
+ void update_flag (uint flag, bool add)
401
+ {
402
+ Xot::update_flag(&flags, flag, add);
403
+ }
404
+
397
405
  bool has_flag (uint flag) const
398
406
  {
399
407
  return Xot::has_flag(flags, flag);
@@ -408,7 +416,19 @@ namespace Reflex
408
416
 
409
417
  void do_sort_children ()
410
418
  {
411
- 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;
412
432
 
413
433
  size_t size = children.size();
414
434
  if (size >= USHRT_MAX)
@@ -422,20 +442,10 @@ namespace Reflex
422
442
  have_z |= child->frame().z != 0;
423
443
  }
424
444
 
425
- if (!have_z)
426
- {
427
- pchildren_sorted.reset();
428
- return;
429
- }
430
-
431
- if (!pchildren_sorted)
432
- {
433
- pchildren_sorted.reset(
434
- new ChildList(children.begin(), children.end()));
435
- }
445
+ if (!have_z) return;
436
446
 
437
447
  std::sort(
438
- pchildren_sorted->begin(), pchildren_sorted->end(),
448
+ pchildren_for_loop->begin(), pchildren_for_loop->end(),
439
449
  [](const auto& a, const auto& b)
440
450
  {
441
451
  auto *aa = a->self.get(), *bb = b->self.get();
@@ -739,15 +749,58 @@ namespace Reflex
739
749
  };// LayoutContext
740
750
 
741
751
 
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
+
742
771
  static void
743
- call_children (View* parent, std::function<bool(View*)> fun, bool sort = true)
772
+ call_children (View* parent, std::function<bool(View*)> fun)
744
773
  {
745
- auto* children = parent->self->children(false, sort);
774
+ auto* children = parent->self->children_for_loop();
746
775
  if (!children) return;
747
776
 
777
+ LoopDepthGuard depth_guard(parent->self.get());
778
+
748
779
  for (auto it = children->rbegin(), end = children->rend(); it != end; ++it)
749
780
  {
750
- if (!fun(it->get()))
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()))
751
804
  break;
752
805
  }
753
806
  }
@@ -865,7 +918,7 @@ namespace Reflex
865
918
  self->update_body_frame();
866
919
 
867
920
  if (moved && event.dz() != 0 && self->parent)
868
- self->parent->self->sort_children(true);
921
+ self->parent->self->sort_children();
869
922
 
870
923
  if ((moved || resized) && self->parent)
871
924
  self->parent->self->add_flag(View::Data::FIT_TO_CONTENT);
@@ -967,10 +1020,10 @@ namespace Reflex
967
1020
  view->on_activate(&e);
968
1021
  if (e.is_blocked()) return;
969
1022
 
970
- call_children(view, [&](View* child) {
1023
+ call_children_unsafe(view, [&](View* child) {
971
1024
  View_activate_tree(child, &e);
972
1025
  return !e.is_blocked();
973
- }, false);
1026
+ });
974
1027
  }
975
1028
 
976
1029
  void
@@ -981,10 +1034,10 @@ namespace Reflex
981
1034
 
982
1035
  Event e = event->dup();
983
1036
 
984
- call_children(view, [&](View* child) {
1037
+ call_children_unsafe(view, [&](View* child) {
985
1038
  View_deactivate_tree(child, &e);
986
1039
  return !e.is_blocked();
987
- }, false);
1040
+ });
988
1041
 
989
1042
  if (e.is_blocked()) return;
990
1043
 
@@ -1172,11 +1225,9 @@ namespace Reflex
1172
1225
  Style_override(pstyle, st);
1173
1226
  }
1174
1227
 
1175
- const Style& style = View_get_style(view);
1176
- if (Style_has_variable_lengths(style))
1177
- self->add_flag(View::Data::HAS_VARIABLE_LENGTHS);
1178
- else
1179
- 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)));
1180
1231
 
1181
1232
  self->add_flag(View::Data::APPLY_STYLE);
1182
1233
  }
@@ -1205,20 +1256,6 @@ namespace Reflex
1205
1256
  }
1206
1257
  }
1207
1258
 
1208
- static void
1209
- remove_children (View* view, View::ChildList* children)
1210
- {
1211
- assert(children);
1212
-
1213
- int size = (int) children->size();
1214
- for (int i = size - 1; i >= 0; --i)
1215
- {
1216
- View* child = (*children)[i].get();
1217
- if (child->self->check_and_remove_flag(View::Data::REMOVE_FROM_PARENT))
1218
- view->remove_child(child);
1219
- }
1220
- }
1221
-
1222
1259
  void
1223
1260
  View_update_tree (View* view, const UpdateEvent& event)
1224
1261
  {
@@ -1227,16 +1264,20 @@ namespace Reflex
1227
1264
 
1228
1265
  View::Data* self = view->self.get();
1229
1266
 
1230
- self->add_flag(View::Data::UPDATING);
1267
+ self->update_children_for_loop(view);
1231
1268
 
1232
1269
  fire_timers(view, event.now());
1233
1270
 
1234
- View::ChildList* children = self->children();
1271
+ View::ChildList* children = self->children_for_loop();
1235
1272
  if (children)
1236
1273
  {
1237
- size_t size = children->size();
1238
- for (size_t i = 0; i < size; ++i)
1239
- 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
+ }
1240
1281
  }
1241
1282
 
1242
1283
  update_view_shapes(view);
@@ -1259,42 +1300,36 @@ namespace Reflex
1259
1300
  if (self->check_and_remove_flag(View::Data::FIT_TO_CONTENT))
1260
1301
  fit_view_to_content(view);
1261
1302
 
1262
- self->remove_flag(View::Data::UPDATING);
1263
-
1264
- if (self->check_and_remove_flag(View::Data::HAS_CHILDREN_TO_REMOVE))
1265
- remove_children(view, children);
1266
1303
  }
1267
1304
 
1268
1305
  static bool
1269
- use_cache (View* view)
1306
+ use_draw_cache (const View::Data& self)
1270
1307
  {
1271
- View::Data* self = view->self.get();
1272
-
1273
- return
1274
- self->has_flag(View::FLAG_CACHE) ||
1275
- (self->pfilter && *self->pfilter);
1308
+ return self.has_flag(View::FLAG_DRAW_CACHE) || (self.pfilter && *self.pfilter);
1276
1309
  }
1277
1310
 
1278
1311
  static bool
1279
- reset_cache_image (View* view, const Painter& painter)
1312
+ setup_draw_cache (View::Data* self, float density)
1280
1313
  {
1281
- assert(use_cache(view));
1282
- 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
+ }
1283
1321
 
1284
- Image* image = self->pcache_image.get();
1285
- int w = ceil(self->frame.width);
1286
- int h = ceil(self->frame.height);
1322
+ Image* image = self->pdraw_cache.get();
1287
1323
  if (
1288
1324
  image &&
1289
1325
  image->width() == w &&
1290
1326
  image->height() == h &&
1291
- image->pixel_density() == painter.pixel_density())
1327
+ image->pixel_density() == density)
1292
1328
  {
1293
1329
  return false;
1294
1330
  }
1295
1331
 
1296
- self->pcache_image.reset(
1297
- new Image(w, h, Rays::RGBA, painter.pixel_density()));
1332
+ self->pdraw_cache.reset(new Image(w, h, Rays::RGBA, density));
1298
1333
  return true;
1299
1334
  }
1300
1335
 
@@ -1365,11 +1400,15 @@ namespace Reflex
1365
1400
 
1366
1401
  if (event->is_blocked()) return;
1367
1402
 
1368
- View::ChildList* children = self->children(false, true);
1403
+ View::ChildList* children = self->children_for_loop();
1369
1404
  if (children)
1370
1405
  {
1371
- for (auto& child : *children)
1406
+ LoopDepthGuard depth_guard(self);
1407
+
1408
+ for (View::Ref child : *children)
1372
1409
  {
1410
+ if (!child) continue;
1411
+
1373
1412
  if (event->bounds() & child->self->frame)
1374
1413
  View_draw_tree(child.get(), event, offset, clip, scale);
1375
1414
  }
@@ -1388,7 +1427,7 @@ namespace Reflex
1388
1427
  draw_view_to_cache (View* view, DrawEvent* event)
1389
1428
  {
1390
1429
  Painter* view_painter = event->painter();
1391
- Painter cache_painter = view->self->pcache_image->painter();
1430
+ Painter cache_painter = view->self->pdraw_cache->painter();
1392
1431
 
1393
1432
  DrawEvent_set_painter(event, &cache_painter);
1394
1433
 
@@ -1404,34 +1443,26 @@ namespace Reflex
1404
1443
  {
1405
1444
  View::Data* self = view->self.get();
1406
1445
 
1407
- if (!use_cache(view))
1408
- {
1409
- self->pcache_image.reset();
1410
- return false;
1411
- }
1412
-
1413
1446
  Painter* painter = event->painter();
1447
+ bool created = setup_draw_cache(self, painter->pixel_density());
1448
+ if (!self->pdraw_cache)
1449
+ return false;
1414
1450
 
1415
- if (reset_cache_image(view, *painter) || redraw)
1416
- {
1417
- if (!self->pcache_image)
1418
- return false;
1419
-
1451
+ if (created || redraw)
1420
1452
  draw_view_to_cache(view, event);
1421
- }
1422
1453
 
1423
1454
  painter->push_state();
1424
- painter->set_fill(1);
1425
- painter->no_stroke();
1426
- painter->no_shader();
1427
-
1428
- if (self->pfilter && *self->pfilter)
1429
- self->pfilter->apply(painter, *self->pcache_image);
1430
- else
1431
- painter->image(*self->pcache_image, event->bounds());
1455
+ {
1456
+ painter->set_fill(1);
1457
+ painter->no_stroke();
1458
+ painter->no_shader();
1432
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
+ }
1433
1465
  painter->pop_state();
1434
-
1435
1466
  return true;
1436
1467
  }
1437
1468
 
@@ -1570,6 +1601,26 @@ namespace Reflex
1570
1601
  }
1571
1602
  }
1572
1603
 
1604
+ void
1605
+ View_call_text_event (View* view, TextEvent* event)
1606
+ {
1607
+ if (!view)
1608
+ argument_error(__FILE__, __LINE__);
1609
+ if (!event)
1610
+ argument_error(__FILE__, __LINE__);
1611
+
1612
+ TextEvent e = event->dup();
1613
+ view->on_text(&e);
1614
+ if (e.is_blocked()) return;
1615
+
1616
+ switch (e.action())
1617
+ {
1618
+ case TextEvent::PREEDIT: view->on_text_preedit(&e); break;
1619
+ case TextEvent::COMMIT: view->on_text_commit(&e); break;
1620
+ default: break;
1621
+ }
1622
+ }
1623
+
1573
1624
  static void
1574
1625
  call_pointer_events_for_each_child (View* parent, PointerEvent* event)
1575
1626
  {
@@ -1587,8 +1638,17 @@ namespace Reflex
1587
1638
  if (view->self->pbody)
1588
1639
  view->self->pbody->awake();
1589
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
+
1590
1650
  view->on_pointer(event);
1591
- if (event->is_blocked()) return;
1651
+ if (block_if_canceled()) return;
1592
1652
 
1593
1653
  switch ((*event)[0].action())
1594
1654
  {
@@ -1600,6 +1660,8 @@ namespace Reflex
1600
1660
  case Pointer::LEAVE: view->on_pointer_leave(event); break;
1601
1661
  default: break;
1602
1662
  }
1663
+
1664
+ block_if_canceled();
1603
1665
  }
1604
1666
 
1605
1667
  static void
@@ -1635,7 +1697,7 @@ namespace Reflex
1635
1697
  if (!event)
1636
1698
  argument_error(__FILE__, __LINE__);
1637
1699
 
1638
- if (view->hidden() || event->empty())
1700
+ if (event->empty() || view->hidden())
1639
1701
  return;
1640
1702
 
1641
1703
  Window* win = view->window();
@@ -1688,6 +1750,25 @@ namespace Reflex
1688
1750
  view->on_wheel(&e);
1689
1751
  }
1690
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
+
1691
1772
  void
1692
1773
  View_call_midi_event (View* view, MIDIEvent* event)
1693
1774
  {
@@ -1738,25 +1819,6 @@ namespace Reflex
1738
1819
  view->on_control_change(&e);
1739
1820
  }
1740
1821
 
1741
- void
1742
- View_call_contact_event (View* view, ContactEvent* event)
1743
- {
1744
- if (!view)
1745
- argument_error(__FILE__, __LINE__);
1746
- if (!event)
1747
- argument_error(__FILE__, __LINE__);
1748
-
1749
- ContactEvent e = event->dup();
1750
- view->on_contact(&e);
1751
-
1752
- switch (e.action())
1753
- {
1754
- case ContactEvent::BEGIN: view->on_contact_begin(&e); break;
1755
- case ContactEvent::END: view->on_contact_end(&e); break;
1756
- default: break;
1757
- }
1758
- }
1759
-
1760
1822
 
1761
1823
  View::View (const char* name)
1762
1824
  {
@@ -1817,13 +1879,14 @@ namespace Reflex
1817
1879
  void
1818
1880
  View::redraw ()
1819
1881
  {
1820
- 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)))
1821
1884
  return;
1822
1885
 
1823
1886
  self->add_flag(Data::REDRAW);
1824
1887
 
1825
- if (self->parent)
1826
- self->parent->redraw();
1888
+ if (parent)
1889
+ parent->redraw();
1827
1890
  else if (self->window)
1828
1891
  self->window->redraw();
1829
1892
  }
@@ -1872,6 +1935,39 @@ namespace Reflex
1872
1935
  redraw();
1873
1936
  }
1874
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
+
1875
1971
  static void
1876
1972
  get_from_parent_matrix (Matrix* m, const View* view)
1877
1973
  {
@@ -2004,11 +2100,17 @@ namespace Reflex
2004
2100
  assert(it != end);
2005
2101
 
2006
2102
  children->erase(it);
2007
- if (children->empty())
2103
+
2104
+ View::ChildList* children_for_loop = parent->self->pchildren_for_loop.get();
2105
+ if (children_for_loop)
2008
2106
  {
2009
- parent->self->pchildren.reset();
2010
- 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();
2011
2110
  }
2111
+
2112
+ if (children->empty())
2113
+ parent->self->pchildren.reset();
2012
2114
  }
2013
2115
 
2014
2116
  void
@@ -2019,6 +2121,9 @@ namespace Reflex
2019
2121
  if (child == this)
2020
2122
  argument_error(__FILE__, __LINE__);
2021
2123
 
2124
+ if (World_is_stepping(self->pchild_world.get()))
2125
+ physics_error(__FILE__, __LINE__, "world is stepping now");
2126
+
2022
2127
  bool found = std::find(child_begin(), child_end(), child) != child_end();
2023
2128
  bool belong = child->parent() == this;
2024
2129
  if (found && belong)
@@ -2034,10 +2139,8 @@ namespace Reflex
2034
2139
 
2035
2140
  View* prev_parent = child->parent();
2036
2141
  set_parent(child, this);
2037
-
2038
2142
  if (prev_parent)
2039
2143
  erase_child_from_children(prev_parent, child);
2040
-
2041
2144
  self->sort_children();
2042
2145
 
2043
2146
  update_view_layout(this);
@@ -2051,6 +2154,9 @@ namespace Reflex
2051
2154
  if (child == this)
2052
2155
  argument_error(__FILE__, __LINE__);
2053
2156
 
2157
+ if (World_is_stepping(self->pchild_world.get()))
2158
+ physics_error(__FILE__, __LINE__, "world is stepping now");
2159
+
2054
2160
  bool found = std::find(child_begin(), child_end(), child) != child_end();
2055
2161
  bool belong = child->parent() == this;
2056
2162
  if (!found && !belong)
@@ -2058,19 +2164,11 @@ namespace Reflex
2058
2164
  else if (found != belong)
2059
2165
  invalid_state_error(__FILE__, __LINE__);
2060
2166
 
2061
- if (self->has_flag(Data::UPDATING))
2062
- {
2063
- // delay removing child to avoid breaking child list looped on View_update_tree()
2064
- self->add_flag(Data::HAS_CHILDREN_TO_REMOVE);
2065
- child->self->add_flag(Data::REMOVE_FROM_PARENT);
2066
- }
2067
- else
2068
- {
2069
- set_parent(child, NULL);
2070
- erase_child_from_children(this, child);
2071
- self->sort_children();
2072
- update_view_layout(this);
2073
- }
2167
+ set_parent(child, NULL);
2168
+ erase_child_from_children(this, child);
2169
+ self->sort_children();
2170
+
2171
+ update_view_layout(this);
2074
2172
  }
2075
2173
 
2076
2174
  void
@@ -2245,10 +2343,7 @@ namespace Reflex
2245
2343
  void
2246
2344
  View::set_shape (Shape* shape)
2247
2345
  {
2248
- if (!shape)
2249
- self->add_flag(Data::NO_SHAPE);
2250
- else
2251
- self->remove_flag(Data::NO_SHAPE);
2346
+ self->update_flag(Data::NO_SHAPE, !shape);
2252
2347
 
2253
2348
  Shape::Ref& pshape = self->pshape;
2254
2349
  if (shape == pshape.get()) return;
@@ -2501,27 +2596,6 @@ namespace Reflex
2501
2596
  return self->frame;
2502
2597
  }
2503
2598
 
2504
- Bounds
2505
- View::content_bounds () const
2506
- {
2507
- Bounds bounds = Rays::invalid_bounds();
2508
- self->each_shape([&](const Shape* shape)
2509
- {
2510
- if (!shape || !Shape_has_frame(*shape))
2511
- return;
2512
-
2513
- Bounds frame = shape->frame();
2514
- if (frame) bounds |= frame;
2515
- });
2516
- return bounds;
2517
- }
2518
-
2519
- void
2520
- View::fit_to_content ()
2521
- {
2522
- self->add_flag(View::Data::FIT_TO_CONTENT);
2523
- }
2524
-
2525
2599
  void
2526
2600
  View::set_zoom (float zoom)
2527
2601
  {
@@ -3052,6 +3126,21 @@ namespace Reflex
3052
3126
  {
3053
3127
  }
3054
3128
 
3129
+ void
3130
+ View::on_text (TextEvent* e)
3131
+ {
3132
+ }
3133
+
3134
+ void
3135
+ View::on_text_preedit (TextEvent* e)
3136
+ {
3137
+ }
3138
+
3139
+ void
3140
+ View::on_text_commit (TextEvent* e)
3141
+ {
3142
+ }
3143
+
3055
3144
  void
3056
3145
  View::on_pointer (PointerEvent* e)
3057
3146
  {
@@ -3094,58 +3183,58 @@ namespace Reflex
3094
3183
  }
3095
3184
 
3096
3185
  void
3097
- View::on_midi (MIDIEvent* e)
3186
+ View::on_capture (CaptureEvent* e)
3098
3187
  {
3099
3188
  }
3100
3189
 
3101
3190
  void
3102
- View::on_note (NoteEvent* e)
3191
+ View::on_timer (TimerEvent* e)
3103
3192
  {
3104
3193
  }
3105
3194
 
3106
- void
3107
- View::on_note_on (NoteEvent* e)
3195
+ bool
3196
+ View::will_contact (View* v)
3108
3197
  {
3198
+ return true;
3109
3199
  }
3110
3200
 
3111
3201
  void
3112
- View::on_note_off (NoteEvent* e)
3202
+ View::on_contact (ContactEvent* e)
3113
3203
  {
3114
3204
  }
3115
3205
 
3116
3206
  void
3117
- View::on_control_change (ControlChangeEvent* e)
3207
+ View::on_contact_begin (ContactEvent* e)
3118
3208
  {
3119
3209
  }
3120
3210
 
3121
3211
  void
3122
- View::on_capture (CaptureEvent* e)
3212
+ View::on_contact_end (ContactEvent* e)
3123
3213
  {
3124
3214
  }
3125
3215
 
3126
3216
  void
3127
- View::on_timer (TimerEvent* e)
3217
+ View::on_midi (MIDIEvent* e)
3128
3218
  {
3129
3219
  }
3130
3220
 
3131
- bool
3132
- View::will_contact (View* v)
3221
+ void
3222
+ View::on_note (NoteEvent* e)
3133
3223
  {
3134
- return true;
3135
3224
  }
3136
3225
 
3137
3226
  void
3138
- View::on_contact (ContactEvent* e)
3227
+ View::on_note_on (NoteEvent* e)
3139
3228
  {
3140
3229
  }
3141
3230
 
3142
3231
  void
3143
- View::on_contact_begin (ContactEvent* e)
3232
+ View::on_note_off (NoteEvent* e)
3144
3233
  {
3145
3234
  }
3146
3235
 
3147
3236
  void
3148
- View::on_contact_end (ContactEvent* e)
3237
+ View::on_control_change (ControlChangeEvent* e)
3149
3238
  {
3150
3239
  }
3151
3240