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
@@ -0,0 +1,156 @@
1
+ %w[xot rays reflex]
2
+ .map {|s| File.expand_path "../../#{s}/lib", __dir__}
3
+ .each {|s| $:.unshift s if !$:.include?(s) && File.directory?(s)}
4
+
5
+ require 'reflex'
6
+
7
+
8
+ # How a window can look and behave: which parts of the titlebar it shows,
9
+ # whether it draws a shadow, whether the alpha you draw with lets the desktop
10
+ # show through, and whether it can be closed, minimized or resized.
11
+ #
12
+ # Hiding a part of the titlebar takes its function away too. With the
13
+ # background hidden the window can no longer be dragged or zoomed by the strip
14
+ # the titlebar sat on, since the window itself draws there and gets the mouse
15
+ # events.
16
+ #
17
+ # The two windows differ only in what they draw behind the circles, so a
18
+ # see-through background and a translucent one can be compared. On macOS the
19
+ # shadow of a see-through window is made from what was drawn, so it follows
20
+ # the circles. Windows draws it around the frame instead.
21
+ #
22
+ # A window that lets the pointer through gets no pointer events at all. It
23
+ # cannot be clicked, dragged or activated, and the click reaches whatever sits
24
+ # behind it. Drag the two windows over each other to see where a click lands,
25
+ # the counter says which one got it. Only one window at a time can do it, so
26
+ # there is always another one left to click on.
27
+ #
28
+ # Pressing 9 again keeps the pointer going through only where the window
29
+ # drew little: with pointer_through_alpha at 0.5, the see-through window takes
30
+ # a click on its circles and passes one on its empty background, and the
31
+ # translucent window passes clicks through its 0.3 background too. The
32
+ # titlebar always takes the pointer. A third press turns it off.
33
+ #
34
+ # An unlisted window is still there on screen, but it leaves the window
35
+ # overviews: Mission Control on macOS, the taskbar and alt-tab on Windows.
36
+ # Toggle it and open the overview to watch the window drop out of the list
37
+ # while staying right where it is.
38
+ #
39
+ # Not every platform can do all of this, and the ones that cannot say so.
40
+ #
41
+ # 1: titlebar buttons, 2: titlebar background, 3: both
42
+ # 4: shadow, 5: transparent
43
+ # 6: closable, 7: minimizable, 8: resizable
44
+ # 9: pointer through, 0: unlisted
45
+ # ESC: quit
46
+ class StyledWindow < Reflex::Window
47
+
48
+ PARTS = [:buttons, :background]
49
+
50
+ @@message = nil
51
+
52
+ def initialize (title, x, alpha)
53
+ super title: title, frame: [x, 100, 360, 360], transparent: true
54
+ @alpha = alpha
55
+ @t = 0.0
56
+ @clicks = 0
57
+ painter.font = Reflex::Font.new nil, 16
58
+ end
59
+
60
+ def on_draw (e)
61
+ @t += 0.03
62
+ p = e.painter
63
+
64
+ # the alpha here is what lets the desktop show through
65
+ p.background 0, 0, 0, @alpha
66
+
67
+ 8.times do |i|
68
+ a = @t + i * Math::PI / 4
69
+ x = 180 + Math.cos(a) * 100
70
+ y = 180 + Math.sin(a) * 100
71
+ p.fill((Math.sin(@t + i) + 1) / 2, 0.6, 1)
72
+ p.ellipse x - 20, y - 20, 40, 40
73
+ end
74
+
75
+ # something that stays put, to aim a click at
76
+ p.fill 1, 0.8, 0.2
77
+ p.ellipse 150, 150, 60, 60
78
+
79
+ p.fill 1
80
+ p.text "titlebar: #{titlebar.inspect}", 10, 10
81
+ p.text "shadow: #{shadow?}, transparent: #{transparent?}, " \
82
+ "unlisted: #{unlisted?}", 10, 30
83
+ p.text "closable: #{closable?}, minimizable: #{minimizable?}, " \
84
+ "resizable: #{resizable?}", 10, 50
85
+ p.text "pointer through: #{pointer_through_state}, clicks: #{@clicks}", 10, 70
86
+ p.text "#{e.fps.to_i} FPS", 10, 90
87
+ p.text '1: buttons, 2: background, 3: both', 10, 110
88
+ p.text '4: shadow, 5: transparent', 10, 130
89
+ p.text '6: closable, 7: minimizable, 8: resizable', 10, 150
90
+ p.text '9: pointer through, 0: unlisted, ESC: quit', 10, 170
91
+
92
+ if @@message
93
+ p.fill 1, 0.4, 0.4
94
+ p.text @@message, 10, 190
95
+ end
96
+ end
97
+
98
+ def on_update (e) = redraw
99
+
100
+ def on_pointer_down (e)
101
+ @clicks += 1
102
+ end
103
+
104
+ def on_key_down (e)
105
+ case e.chars
106
+ when '1' then change {|w| w.toggle_titlebar :buttons}
107
+ when '2' then change {|w| w.toggle_titlebar :background}
108
+ when '3' then change {|w| w.titlebar = w.titlebar.empty? ? PARTS : []}
109
+ when '4' then change {|w| w.shadow = !w.shadow?}
110
+ when '5' then change {|w| w.transparent = !w.transparent?}
111
+ when '6' then change {|w| w.closable = !w.closable?}
112
+ when '7' then change {|w| w.minimizable = !w.minimizable?}
113
+ when '8' then change {|w| w.resizable = !w.resizable?}
114
+ when '9' then change {|w| w.cycle_pointer_through w.equal?(self)}
115
+ when '0' then change {|w| w.unlisted = !w.unlisted?}
116
+ end
117
+ Reflex.quit if e.key == :escape
118
+ end
119
+
120
+ def toggle_titlebar (part)
121
+ parts = titlebar
122
+ self.titlebar = parts.include?(part) ? parts - [part] : parts + [part]
123
+ end
124
+
125
+ # off -> everything through -> only the pixels at alpha 0.5 or less -> off
126
+ def cycle_pointer_through (mine)
127
+ if !mine || (pointer_through? && pointer_through_alpha < 1)
128
+ self.pointer_through = false
129
+ elsif !pointer_through?
130
+ self.pointer_through = true
131
+ self.pointer_through_alpha = 1
132
+ else
133
+ self.pointer_through_alpha = 0.5
134
+ end
135
+ end
136
+
137
+ def pointer_through_state ()
138
+ return 'false' if !pointer_through?
139
+ return 'all' if pointer_through_alpha >= 1
140
+ return "alpha <= #{pointer_through_alpha}"
141
+ end
142
+
143
+ def change (&block)
144
+ @@message = nil
145
+ Reflex::Application.instance.windows.each(&block)
146
+ rescue ArgumentError, NotImplementedError => e
147
+ @@message = e.message
148
+ end
149
+
150
+ end# StyledWindow
151
+
152
+
153
+ Reflex.start do
154
+ StyledWindow.new('see-through', 100, 0.0).show
155
+ StyledWindow.new('translucent', 500, 0.3).show
156
+ end
data/src/application.cpp CHANGED
@@ -4,8 +4,8 @@
4
4
  #include "reflex/exception.h"
5
5
  #include "reflex/debug.h"
6
6
  #include "window.h"
7
- #include "gamepad.h"
8
7
  #include "midi.h"
8
+ #include "gamepad.h"
9
9
 
10
10
 
11
11
  namespace Reflex
@@ -20,13 +20,47 @@ namespace Reflex
20
20
  }// global
21
21
 
22
22
 
23
+ bool
24
+ Application_should_quit (Application* app)
25
+ {
26
+ if (!app || !app->self->started)
27
+ return false;
28
+
29
+ if (app->background_menu())
30
+ return false;
31
+
32
+ if (app->background() && app->menu())
33
+ return false;
34
+
35
+ return Reflex::Window_all().empty();
36
+ }
37
+
38
+ void
39
+ Application_cleanup (Application* app)
40
+ {
41
+ MIDI_fin(app);
42
+ Gamepad_fin(app);
43
+ }
44
+
45
+ void
46
+ Application_call_quit (Application* app)
47
+ {
48
+ Application_guard([&]()
49
+ {
50
+ app->quit();
51
+ });
52
+ }
53
+
23
54
  void
24
- Application_call_start (Application* app, Event* e)
55
+ Application_call_start_event (Application* app, Event* e)
25
56
  {
26
- app->on_start(e);
57
+ if (app->self->started) return;
27
58
 
28
- Gamepad_init(app);
29
- MIDI_init(app);
59
+ Application_guard([&]()
60
+ {
61
+ app->on_start(e);
62
+ app->self->started = true;
63
+ });
30
64
  }
31
65
 
32
66
  static void
@@ -37,32 +71,98 @@ namespace Reflex
37
71
  }
38
72
 
39
73
  void
40
- Application_call_quit (Application* app, Event* e)
74
+ Application_call_quit_event (Application* app, Event* e)
41
75
  {
42
76
  if (app->self->quitting) return;
43
77
 
44
- app->on_quit(e);
45
- if (e->is_blocked()) return;
78
+ Application_guard([&]()
79
+ {
80
+ app->on_quit(e);
81
+ if (e->is_blocked()) return;
46
82
 
47
- app->self->quitting = true;
83
+ app->self->quitting = true;
48
84
 
49
- close_all_windows(app);
50
- MIDI_fin(app);
51
- Gamepad_fin(app);
85
+ close_all_windows(app);
86
+ });
87
+ }
88
+
89
+ void
90
+ Application_call_device_connect_event (Application* app, Device* device)
91
+ {
92
+ Application_guard([&]()
93
+ {
94
+ DeviceEvent e(device);
95
+ app->on_device_connect(&e);
96
+ });
97
+ }
98
+
99
+ void
100
+ Application_call_device_disconnect_event (Application* app, Device* device)
101
+ {
102
+ Application_guard([&]()
103
+ {
104
+ DeviceEvent e(device);
105
+ app->on_device_disconnect(&e);
106
+ });
107
+ }
108
+
109
+ void
110
+ Application_call_motion_event (Application* app, MotionEvent* e)
111
+ {
112
+ Application_guard([&]()
113
+ {
114
+ app->on_motion(e);
115
+ });
116
+ }
117
+
118
+ void
119
+ Application_call_preference_event (Application* app, Event* e)
120
+ {
121
+ Application_guard([&]()
122
+ {
123
+ app->on_preference(e);
124
+ });
52
125
  }
53
126
 
54
127
  void
55
- Application_call_device_connect (Application* app, Device* device)
128
+ Application_call_about_event (Application* app, Event* e)
56
129
  {
57
- DeviceEvent e(device);
58
- app->on_device_connect(&e);
130
+ Application_guard([&]()
131
+ {
132
+ app->on_about(e);
133
+ });
134
+ }
135
+
136
+ bool
137
+ Application_has_exception ()
138
+ {
139
+ Application* app = global::instance;
140
+ return app && app->self->exception;
141
+ }
142
+
143
+ bool
144
+ Application_keep_exception (std::exception_ptr exception)
145
+ {
146
+ Application* app = global::instance;
147
+ if (!app || !app->self->running)
148
+ return false;
149
+
150
+ // the first one is the cause, so keep it and drop the rest
151
+ if (!app->self->exception)
152
+ app->self->exception = exception;
153
+
154
+ Application_stop(app);
155
+ return true;
59
156
  }
60
157
 
61
158
  void
62
- Application_call_device_disconnect (Application* app, Device* device)
159
+ Application_throw_exception (Application* app)
63
160
  {
64
- DeviceEvent e(device);
65
- app->on_device_disconnect(&e);
161
+ std::exception_ptr exception = app->self->exception;
162
+ if (!exception) return;
163
+
164
+ app->self->exception = NULL;
165
+ std::rethrow_exception(exception);
66
166
  }
67
167
 
68
168
  Application*
@@ -72,6 +172,12 @@ namespace Reflex
72
172
  }
73
173
 
74
174
 
175
+ Application::Data::Data ()
176
+ : name(Application_get_default_name())
177
+ {
178
+ }
179
+
180
+
75
181
  Application::Application ()
76
182
  : self(Application_create_data())
77
183
  {
@@ -120,6 +226,41 @@ namespace Reflex
120
226
  return const_cast<Application*>(this)->menu();
121
227
  }
122
228
 
229
+ void
230
+ Application::set_background (bool state)
231
+ {
232
+ if (state == self->background)
233
+ return;
234
+
235
+ self->background = state;
236
+ Application_set_background(this, state);
237
+ }
238
+
239
+ bool
240
+ Application::background () const
241
+ {
242
+ return self->background;
243
+ }
244
+
245
+ void
246
+ Application::set_background_menu (Menu* menu)
247
+ {
248
+ self->background_menu = menu;
249
+ Application_set_background_menu(this, menu);
250
+ }
251
+
252
+ Menu*
253
+ Application::background_menu ()
254
+ {
255
+ return self->background_menu.get();
256
+ }
257
+
258
+ const Menu*
259
+ Application::background_menu () const
260
+ {
261
+ return const_cast<Application*>(this)->background_menu();
262
+ }
263
+
123
264
  Application::window_iterator
124
265
  Application::window_begin ()
125
266
  {
data/src/application.h CHANGED
@@ -4,6 +4,9 @@
4
4
  #define __REFLEX_SRC_APPLICATION_H__
5
5
 
6
6
 
7
+ #include <exception>
8
+ #include <type_traits>
9
+ #include <utility>
7
10
  #include "reflex/application.h"
8
11
  #include "reflex/menu.h"
9
12
 
@@ -17,25 +20,107 @@ namespace Reflex
17
20
 
18
21
  String name;
19
22
 
20
- Menu::Ref menu;
23
+ Menu::Ref menu, background_menu;
21
24
 
22
- bool quitting = false;
25
+ bool background = false;
26
+
27
+ bool started = false;
28
+
29
+ bool running = false;
30
+
31
+ bool quitting = false;
32
+
33
+ std::exception_ptr exception;
34
+
35
+ Data ();
23
36
 
24
37
  };// Application::Data
25
38
 
26
39
 
40
+ bool Application_should_quit (Application* app);
41
+
42
+ void Application_cleanup (Application* app);
43
+
44
+ void Application_call_quit (Application* app);
45
+
46
+ void Application_call_start_event (Application* app, Event* e);
47
+
48
+ void Application_call_quit_event (Application* app, Event* e);
49
+
50
+ void Application_call_device_connect_event (Application* app, Device* device);
51
+
52
+ void Application_call_device_disconnect_event (Application* app, Device* device);
53
+
54
+ void Application_call_motion_event (Application* app, MotionEvent* e);
55
+
56
+ void Application_call_preference_event (Application* app, Event* e);
57
+
58
+ void Application_call_about_event (Application* app, Event* e);
59
+
60
+ bool Application_has_exception ();
61
+
62
+ bool Application_keep_exception (std::exception_ptr exception);
63
+
64
+ void Application_throw_exception (Application* app);
65
+
66
+
27
67
  Application::Data* Application_create_data ();
28
68
 
29
- void Application_set_menu (Application* app, Menu* menu);
69
+ String Application_get_default_name ();
70
+
71
+ void Application_stop (Application* app);
30
72
 
73
+ void Application_set_menu (Application* app, Menu* menu);
31
74
 
32
- void Application_call_start (Application* app, Event* e);
75
+ void Application_set_background (Application* app, bool state);
33
76
 
34
- void Application_call_quit (Application* app, Event* e);
77
+ void Application_set_background_menu (Application* app, Menu* menu);
35
78
 
36
- void Application_call_device_connect (Application* app, Device* device);
37
79
 
38
- void Application_call_device_disconnect (Application* app, Device* device);
80
+ template <typename FUN, typename RET>
81
+ inline RET
82
+ Application_guard (FUN&& fun, RET fallback)
83
+ {
84
+ // Runs 'fun' so that no C++ exception gets out of it while start()
85
+ // runs the event loop. The exception is kept, the loop is stopped,
86
+ // and start() throws it again after the loop returns. Once one is
87
+ // kept, later calls return 'fallback' without running 'fun'.
88
+ //
89
+ // Where to use it:
90
+ // 1. Platform code never calls anything that reaches on_* by itself,
91
+ // not even close() or quit(). It goes through a Foo_call_* function
92
+ // in src/, and those are the places to guard.
93
+ // 2. Guard the body of Foo_call_*. The argument checks stay outside,
94
+ // a bug inside reflex should fail right there.
95
+ // 3. Two exceptions: the window procedures on windows, since an
96
+ // exception can not cross the kernel callback boundary, and the
97
+ // drawing calls of each platform loop, since rays can throw there.
98
+
99
+ if (Application_has_exception())
100
+ return fallback;
101
+
102
+ try
103
+ {
104
+ return fun();
105
+ }
106
+ catch (...)
107
+ {
108
+ if (!Application_keep_exception(std::current_exception()))
109
+ throw;
110
+ }
111
+ return fallback;
112
+ }
113
+
114
+ template <typename FUN>
115
+ inline auto
116
+ Application_guard (FUN&& fun) -> decltype(fun())
117
+ {
118
+ typedef decltype(fun()) RET;
119
+ if constexpr (std::is_void<RET>::value)
120
+ Application_guard([&]() {fun(); return 0;}, 0);
121
+ else
122
+ return Application_guard(std::forward<FUN>(fun), RET());
123
+ }
39
124
 
40
125
 
41
126
  }// Reflex
@@ -0,0 +1,113 @@
1
+ #include "color_picker.h"
2
+
3
+
4
+ #include "reflex/exception.h"
5
+ #include "application.h"
6
+
7
+
8
+ namespace Reflex
9
+ {
10
+
11
+
12
+ void
13
+ ColorPicker_call_color_event (ColorPicker* picker, ColorEvent* event)
14
+ {
15
+ if (!picker)
16
+ argument_error(__FILE__, __LINE__);
17
+ if (!event)
18
+ argument_error(__FILE__, __LINE__);
19
+
20
+ Application_guard([&]()
21
+ {
22
+ picker->on_color(event);
23
+ });
24
+ }
25
+
26
+ void
27
+ ColorPicker_call_close_event (ColorPicker* picker, Event* event)
28
+ {
29
+ if (!picker)
30
+ argument_error(__FILE__, __LINE__);
31
+ if (!event)
32
+ argument_error(__FILE__, __LINE__);
33
+
34
+ Application_guard([&]()
35
+ {
36
+ picker->on_close(event);
37
+ });
38
+ }
39
+
40
+
41
+ ColorPicker::ColorPicker ()
42
+ {
43
+ }
44
+
45
+ ColorPicker::~ColorPicker ()
46
+ {
47
+ }
48
+
49
+ void
50
+ ColorPicker::pick_color ()
51
+ {
52
+ ColorPicker_show(this, NULL);
53
+ }
54
+
55
+ void
56
+ ColorPicker::pick_color (const Color& initial)
57
+ {
58
+ ColorPicker_show(this, &initial);
59
+ }
60
+
61
+ void
62
+ ColorPicker::set_owner (Window* window)
63
+ {
64
+ self->owner = window;
65
+ }
66
+
67
+ Window*
68
+ ColorPicker::owner ()
69
+ {
70
+ return self->owner;
71
+ }
72
+
73
+ const Window*
74
+ ColorPicker::owner () const
75
+ {
76
+ return const_cast<ColorPicker*>(this)->owner();
77
+ }
78
+
79
+ void
80
+ ColorPicker::set_alpha (bool state)
81
+ {
82
+ self->alpha = state;
83
+ }
84
+
85
+ bool
86
+ ColorPicker::alpha () const
87
+ {
88
+ return self->alpha;
89
+ }
90
+
91
+ void
92
+ ColorPicker::on_color (ColorEvent* e)
93
+ {
94
+ }
95
+
96
+ void
97
+ ColorPicker::on_close (Event* e)
98
+ {
99
+ }
100
+
101
+ ColorPicker::operator bool () const
102
+ {
103
+ return true;
104
+ }
105
+
106
+ bool
107
+ ColorPicker::operator ! () const
108
+ {
109
+ return !operator bool();
110
+ }
111
+
112
+
113
+ }// Reflex
@@ -0,0 +1,36 @@
1
+ // -*- c++ -*-
2
+ #pragma once
3
+ #ifndef __REFLEX_SRC_COLOR_PICKER_H__
4
+ #define __REFLEX_SRC_COLOR_PICKER_H__
5
+
6
+
7
+ #include <rays/color.h>
8
+ #include "reflex/color_picker.h"
9
+ #include "reflex/window.h"
10
+
11
+
12
+ namespace Reflex
13
+ {
14
+
15
+
16
+ struct ColorPicker::Data
17
+ {
18
+
19
+ Xot::WeakRef<Window> owner;
20
+
21
+ bool alpha = false;
22
+
23
+ };// ColorPicker::Data
24
+
25
+
26
+ void ColorPicker_show (ColorPicker* picker, const Color* initial);
27
+
28
+ void ColorPicker_call_color_event (ColorPicker* picker, ColorEvent* event);
29
+
30
+ void ColorPicker_call_close_event (ColorPicker* picker, Event* event);
31
+
32
+
33
+ }// Reflex
34
+
35
+
36
+ #endif//EOH