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/menu.cpp CHANGED
@@ -4,12 +4,73 @@
4
4
  #include <algorithm>
5
5
  #include <rays/point.h>
6
6
  #include "reflex/exception.h"
7
+ #include "application.h"
8
+ #include "view.h"
9
+ #include "window.h"
7
10
 
8
11
 
9
12
  namespace Reflex
10
13
  {
11
14
 
12
15
 
16
+ void
17
+ Menu_cancel_active_pointers_for_popup (View* view)
18
+ {
19
+ Window* window = view ? view->window() : Window_get_active();
20
+ if (!window) return;
21
+
22
+ // popup runs a modal event loop that swallows every event until the
23
+ // menu is dismissed, so pointers being pressed would never see their
24
+ // up; canceling them first keeps every pointer stream closed.
25
+ Window_cancel_active_pointers(window);
26
+ }
27
+
28
+ void
29
+ Menu_call_click_event (Menu* menu, Event* event)
30
+ {
31
+ Application_guard([&]()
32
+ {
33
+ menu->on_click(event);
34
+ });
35
+ }
36
+
37
+ void
38
+ Menu_call_show_event (Menu* menu, Event* event)
39
+ {
40
+ Application_guard([&]()
41
+ {
42
+ menu->on_show(event);
43
+ });
44
+ }
45
+
46
+ void
47
+ Menu_call_hide_event (Menu* menu, Event* event)
48
+ {
49
+ Application_guard([&]()
50
+ {
51
+ menu->on_hide(event);
52
+ });
53
+ }
54
+
55
+ void
56
+ Menu_call_open_submenu_event (Menu* menu, Event* event)
57
+ {
58
+ Application_guard([&]()
59
+ {
60
+ menu->on_open_submenu(event);
61
+ });
62
+ }
63
+
64
+ void
65
+ Menu_call_close_submenu_event (Menu* menu, Event* event)
66
+ {
67
+ Application_guard([&]()
68
+ {
69
+ menu->on_close_submenu(event);
70
+ });
71
+ }
72
+
73
+
13
74
  Menu::Data::Data ()
14
75
  {
15
76
  }
@@ -194,9 +255,10 @@ namespace Reflex
194
255
  }
195
256
 
196
257
  void
197
- Menu::set_shortcut (const char* key, uint modifiers)
258
+ Menu::set_shortcut (KeyCode key, uint modifiers)
198
259
  {
199
- if (!key) key = "";
260
+ Menu_validate_shortcut_modifiers(modifiers);
261
+
200
262
  if (key == self->key && modifiers == self->modifiers)
201
263
  return;
202
264
 
@@ -205,10 +267,10 @@ namespace Reflex
205
267
  Menu_update(this);
206
268
  }
207
269
 
208
- const char*
270
+ KeyCode
209
271
  Menu::shortcut_key () const
210
272
  {
211
- return self->key.c_str();
273
+ return self->key;
212
274
  }
213
275
 
214
276
  uint
data/src/menu.h CHANGED
@@ -19,10 +19,12 @@ namespace Reflex
19
19
 
20
20
  Xot::WeakRef<Menu> parent;
21
21
 
22
- String label, key;
22
+ String label;
23
23
 
24
24
  Image image;
25
25
 
26
+ KeyCode key = KEY_NONE;
27
+
26
28
  uint modifiers = MOD_NONE;
27
29
 
28
30
  bool enabled = true;
@@ -50,6 +52,8 @@ namespace Reflex
50
52
 
51
53
  Menu::Data* Menu_create_data ();
52
54
 
55
+ void Menu_validate_shortcut_modifiers (uint modifiers);
56
+
53
57
  void Menu_update (Menu* menu);
54
58
 
55
59
  void Menu_popup (Menu* menu, View* view, coord x, coord y);
@@ -58,6 +62,18 @@ namespace Reflex
58
62
 
59
63
  void Menu_child_removed (Menu* parent, Menu* child);
60
64
 
65
+ void Menu_cancel_active_pointers_for_popup (View* view);
66
+
67
+ void Menu_call_click_event (Menu* menu, Event* event);
68
+
69
+ void Menu_call_show_event (Menu* menu, Event* event);
70
+
71
+ void Menu_call_hide_event (Menu* menu, Event* event);
72
+
73
+ void Menu_call_open_submenu_event (Menu* menu, Event* event);
74
+
75
+ void Menu_call_close_submenu_event (Menu* menu, Event* event);
76
+
61
77
 
62
78
  }// Reflex
63
79
 
data/src/midi.cpp CHANGED
@@ -40,23 +40,24 @@ namespace Reflex
40
40
 
41
41
  enum Type {UNKNOWN, MESSAGE, ERROR};
42
42
 
43
- Type type = UNKNOWN;
43
+ Type type = UNKNOWN;
44
44
 
45
- MIDI::Ref midi;
45
+ MIDI* midi = NULL;
46
46
 
47
47
  Message message;
48
48
 
49
49
  RtMidiError error;
50
50
 
51
- double time = 0;
51
+ double time = 0, delta_time = 0;
52
52
 
53
53
  RtMidiEvent ()
54
54
  : error("")
55
55
  {
56
56
  }
57
57
 
58
- RtMidiEvent (MIDI* midi, const Message& message, double time)
59
- : type(MESSAGE), midi(midi), message(message), error(""), time(time)
58
+ RtMidiEvent (MIDI* midi, const Message& message, double time, double delta_time)
59
+ : type(MESSAGE), midi(midi), message(message), error(""),
60
+ time(time), delta_time(delta_time)
60
61
  {
61
62
  }
62
63
 
@@ -104,13 +105,34 @@ namespace Reflex
104
105
 
105
106
  call_midi_event(midi, event);
106
107
 
107
- Window* win = Window_get_active();
108
- if (!win) return;
108
+ for (auto& win : Window_all())
109
+ {
110
+ MIDIEvent e = event.dup();
111
+ Window_call_midi_event(win, &e);
112
+ }
113
+ }
114
+
115
+ static MIDI::List midis;
109
116
 
110
- Window_call_midi_event(win, &event);
117
+ static MIDI::Ref
118
+ find_midi (MIDI* midi)
119
+ {
120
+ auto it = std::find_if(
121
+ midis.begin(), midis.end(),
122
+ [=](const MIDI::Ref& ref) {return ref.get() == midi;});
123
+ return it == midis.end() ? MIDI::Ref() : *it;
111
124
  }
112
125
 
113
- static Queue<RtMidiEvent> queue;
126
+ static double
127
+ apply_time (MIDI* midi, const RtMidiEvent& event)
128
+ {
129
+ MIDI::Data* self = midi->self.get();
130
+ if (self->time == 0)
131
+ self->time = event.time;
132
+ else
133
+ self->time += event.delta_time;
134
+ return self->time;
135
+ }
114
136
 
115
137
  static void
116
138
  dispatch_midi_event (RtMidiEvent* event)
@@ -118,8 +140,12 @@ namespace Reflex
118
140
  switch (event->type)
119
141
  {
120
142
  case RtMidiEvent::MESSAGE:
121
- call_events(event->midi, &event->message[0], event->time);
143
+ {
144
+ MIDI::Ref midi = find_midi(event->midi);
145
+ if (midi)
146
+ call_events(midi, event->message.data(), apply_time(midi, *event));
122
147
  break;
148
+ }
123
149
 
124
150
  case RtMidiEvent::ERROR:
125
151
  system_error(
@@ -132,6 +158,8 @@ namespace Reflex
132
158
  }
133
159
  }
134
160
 
161
+ static Queue<RtMidiEvent> queue;
162
+
135
163
  static void
136
164
  process_midi_events ()
137
165
  {
@@ -143,23 +171,13 @@ namespace Reflex
143
171
  static void
144
172
  event_callback (double dt, RtMidiEvent::Message* message, void* data)
145
173
  {
146
- MIDI* midi = (MIDI*) data;
147
- MIDI::Data* self = midi->self.get();
148
-
149
- if (self->time == 0)
150
- self->time = Xot::time();
151
- else
152
- self->time += dt;
153
-
154
- queue.push(RtMidiEvent(midi, *message, self->time));
174
+ queue.push(RtMidiEvent((MIDI*) data, *message, Xot::time(), dt));
155
175
  }
156
176
 
157
177
  static void
158
178
  error_callback (RtMidiError::Type type, const std::string& message, void* data)
159
179
  {
160
- MIDI* midi = (MIDI*) data;
161
-
162
- queue.push(RtMidiEvent(midi, RtMidiError(message, type)));
180
+ queue.push(RtMidiEvent((MIDI*) data, RtMidiError(message, type)));
163
181
  }
164
182
 
165
183
  static MIDI_CreateFun midi_create_fun = NULL;
@@ -191,13 +209,11 @@ namespace Reflex
191
209
  self->name = name;
192
210
  }
193
211
 
194
- static MIDI::List midis;
195
-
196
212
  static void
197
213
  add_midi (MIDI* midi)
198
214
  {
199
215
  midis.emplace_back(midi);
200
- Application_call_device_connect(app(), midi);
216
+ Application_call_device_connect_event(app(), midi);
201
217
  }
202
218
 
203
219
  static void
@@ -208,7 +224,7 @@ namespace Reflex
208
224
  if (it == midis.end()) return;
209
225
 
210
226
  midis.erase(it);
211
- Application_call_device_disconnect(app(), ref);
227
+ Application_call_device_disconnect_event(app(), ref);
212
228
  }
213
229
 
214
230
 
@@ -227,7 +243,7 @@ namespace Reflex
227
243
  ~MIDIDeviceManager ()
228
244
  {
229
245
  for (auto& midi : midis)
230
- Application_call_device_disconnect(app(), midi);
246
+ Application_call_device_disconnect_event(app(), midi);
231
247
  }
232
248
 
233
249
  void update ()
@@ -308,8 +324,10 @@ namespace Reflex
308
324
  return;
309
325
  #endif
310
326
 
311
- if (manager)
312
- invalid_state_error(__FILE__, __LINE__);
327
+ if (!app)
328
+ argument_error(__FILE__, __LINE__);
329
+
330
+ if (manager) return;
313
331
 
314
332
  manager.reset(new MIDIDeviceManager());
315
333
  }
@@ -317,8 +335,10 @@ namespace Reflex
317
335
  void
318
336
  MIDI_fin (Application* app)
319
337
  {
320
- if (!manager)
321
- invalid_state_error(__FILE__, __LINE__);
338
+ if (!app)
339
+ argument_error(__FILE__, __LINE__);
340
+
341
+ if (!manager) return;
322
342
 
323
343
  midis.clear();
324
344
  manager.reset();
@@ -337,6 +357,16 @@ namespace Reflex
337
357
  }
338
358
  }
339
359
 
360
+ void
361
+ enable_midi ()
362
+ {
363
+ Application* app_ = app();
364
+ if (!app_)
365
+ invalid_state_error(__FILE__, __LINE__);
366
+
367
+ MIDI_init(app_);
368
+ }
369
+
340
370
 
341
371
  MIDI::MIDI ()
342
372
  {
@@ -9,4 +9,8 @@
9
9
 
10
10
  - (BOOL) callOnStart;
11
11
 
12
+ - (BOOL) isLaunched;
13
+
14
+ - (void) updateStatusItem;
15
+
12
16
  @end// ReflexAppDelegate
@@ -6,17 +6,19 @@
6
6
  #import <Cocoa/Cocoa.h>
7
7
  #include "reflex/event.h"
8
8
  #include "reflex/exception.h"
9
+ #include "../application.h"
10
+ #include "../rays.h"
9
11
  #include "menu.h"
10
12
 
11
13
 
12
14
  static Reflex::Menu::Ref
13
15
  create_menu (
14
16
  const char* label, const char* name, SEL action = NULL,
15
- const char* key = NULL, uint modifiers = Reflex::MOD_COMMAND)
17
+ Reflex::KeyCode key = Reflex::KEY_NONE, uint modifiers = Reflex::MOD_COMMAND)
16
18
  {
17
19
  Reflex::Menu* item = new Reflex::Menu(label);
18
20
  item->set_name(name);
19
- if (key) item->set_shortcut(key, modifiers);
21
+ if (key != Reflex::KEY_NONE) item->set_shortcut(key, modifiers);
20
22
  Reflex::Menu_set_native_action(item, action);
21
23
  return item;
22
24
  }
@@ -40,17 +42,17 @@ create_application_menu (Reflex::Application* application)
40
42
 
41
43
  app->add_child(create_menu(("About" + name).c_str(), "about", @selector(showAbout)));
42
44
  app->add_child(create_sep());
43
- app->add_child(create_menu("Preferences", "preferences", @selector(showPreference), ","));
45
+ app->add_child(create_menu("Preferences", "preferences", @selector(showPreference), KEY_COMMA));
44
46
  app->add_child(create_sep());
45
47
  app->add_child(services.get());
46
48
  app->add_child(create_sep());
47
- app->add_child(create_menu(("Hide" + name).c_str(), "hide", @selector(hide:), "h"));
49
+ app->add_child(create_menu(("Hide" + name).c_str(), "hide", @selector(hide:), KEY_H));
48
50
  app->add_child(create_menu(
49
51
  "Hide Others", "hide_others", @selector(hideOtherApplications:),
50
- "h", MOD_OPTION | MOD_COMMAND));
52
+ KEY_H, MOD_OPTION | MOD_COMMAND));
51
53
  app->add_child(create_menu("ShowAll", "show_all", @selector(unhideAllApplications:)));
52
54
  app->add_child(create_sep());
53
- app->add_child(create_menu(("Quit" + name).c_str(), "quit", @selector(quit), "q"));
55
+ app->add_child(create_menu(("Quit" + name).c_str(), "quit", @selector(quit), KEY_Q));
54
56
 
55
57
  [NSApp setServicesMenu: Menu_get_nssubmenu(services)];
56
58
  if ([NSApp respondsToSelector: @selector(setAppleMenu:)])
@@ -62,9 +64,11 @@ create_application_menu (Reflex::Application* application)
62
64
  static Reflex::Menu::Ref
63
65
  create_window_menu ()
64
66
  {
67
+ using namespace Reflex;
68
+
65
69
  Reflex::Menu::Ref win = create_menu("Window", "window");
66
70
 
67
- win->add_child(create_menu("Minimize", "minimize", @selector(performMiniaturize:), "m"));
71
+ win->add_child(create_menu("Minimize", "minimize", @selector(performMiniaturize:), KEY_M));
68
72
  win->add_child(create_menu("Zoom", "zoom", @selector(performZoom:)));
69
73
  win->add_child(create_sep());
70
74
  win->add_child(create_menu(
@@ -80,7 +84,8 @@ create_window_menu ()
80
84
 
81
85
  {
82
86
  Reflex::Application* application;
83
- bool started;
87
+ NSStatusItem* status_item;
88
+ bool launched;
84
89
  }
85
90
 
86
91
  - (id) init
@@ -89,7 +94,8 @@ create_window_menu ()
89
94
  if (!self) return nil;
90
95
 
91
96
  application = NULL;
92
- started = false;
97
+ status_item = nil;
98
+ launched = false;
93
99
 
94
100
  return self;
95
101
  }
@@ -98,9 +104,20 @@ create_window_menu ()
98
104
  {
99
105
  assert(!application);
100
106
 
107
+ [self clearStatusItem];
108
+
101
109
  [super dealloc];
102
110
  }
103
111
 
112
+ - (void) clearStatusItem
113
+ {
114
+ if (!status_item) return;
115
+
116
+ [NSStatusBar.systemStatusBar removeStatusItem: status_item];
117
+ [status_item release];
118
+ status_item = nil;
119
+ }
120
+
104
121
  - (void) bind: (Reflex::Application*) app
105
122
  {
106
123
  if (!app)
@@ -133,21 +150,59 @@ create_window_menu ()
133
150
 
134
151
  - (BOOL) callOnStart
135
152
  {
136
- if (!application || started)
153
+ if (!application)
137
154
  return YES;
138
155
 
139
156
  Reflex::Event e;
140
- Application_call_start(application, &e);
141
- started = true;
157
+ Application_call_start_event(application, &e);
142
158
 
143
159
  if (e.is_blocked()) [self quit];
144
160
  return !e.is_blocked();
145
161
  }
146
162
 
163
+ - (BOOL) isLaunched
164
+ {
165
+ return launched;
166
+ }
167
+
168
+ - (void) updateStatusItem
169
+ {
170
+ Reflex::Menu* menu = application ? application->background_menu() : NULL;
171
+ if (!menu && application && application->background())
172
+ menu = application->menu();
173
+ if (!menu)
174
+ return [self clearStatusItem];
175
+
176
+ if (!status_item)
177
+ {
178
+ status_item =
179
+ [[NSStatusBar.systemStatusBar statusItemWithLength: NSVariableStatusItemLength]
180
+ retain];
181
+ }
182
+
183
+ NSImage* image =
184
+ menu->image() ? Rays::Bitmap_get_nsimage(menu->image().bitmap()) : nil;
185
+ [image setTemplate: YES];
186
+
187
+ NSString* title = @"";
188
+ if (!image)
189
+ {
190
+ Reflex::String label = menu->label();
191
+ if (label.empty()) label = application->name();
192
+ title = !label.empty()
193
+ ? [NSString stringWithUTF8String: label]
194
+ : NSProcessInfo.processInfo.processName;
195
+ }
196
+
197
+ status_item.button.image = image;
198
+ status_item.button.title = title;
199
+ status_item.menu = Reflex::Menu_get_nssubmenu(menu);
200
+ }
201
+
147
202
  - (void) quit
148
203
  {
149
204
  if (application)
150
- application->quit();
205
+ Application_call_quit(application);
151
206
  else
152
207
  [NSApp terminate: nil];
153
208
  }
@@ -157,7 +212,7 @@ create_window_menu ()
157
212
  if (!application) return;
158
213
 
159
214
  Reflex::Event e;
160
- application->on_preference(&e);
215
+ Application_call_preference_event(application, &e);
161
216
  }
162
217
 
163
218
  - (void) showAbout
@@ -165,7 +220,7 @@ create_window_menu ()
165
220
  if (application)
166
221
  {
167
222
  Reflex::Event e;
168
- application->on_about(&e);
223
+ Application_call_about_event(application, &e);
169
224
  }
170
225
  else
171
226
  [NSApp orderFrontStandardAboutPanel: nil];
@@ -183,31 +238,56 @@ create_window_menu ()
183
238
 
184
239
  - (void) applicationDidFinishLaunching: (NSNotification*) notification
185
240
  {
186
- [NSApp setActivationPolicy: NSApplicationActivationPolicyRegular];
187
- [NSApp activateIgnoringOtherApps: YES];
241
+ if (application)
242
+ Application_set_background(application, application->background());
188
243
 
244
+ launched = true;
189
245
  [self callOnStart];
190
246
  }
191
247
 
192
248
  - (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication*) application
193
249
  {
194
- if (self->application)
250
+ Reflex::Application* app = self->application;
251
+ if (!app) return NSTerminateNow;
252
+
253
+ if (app->self->running && !self.isQuitBySystem)
195
254
  {
196
- Reflex::Event e;
197
- Application_call_quit(self->application, &e);
198
- if (e.is_blocked()) return NSTerminateCancel;
255
+ Application_call_quit(app);
256
+ return NSTerminateCancel;
199
257
  }
200
258
 
259
+ Reflex::Event e;
260
+ Application_call_quit_event(app, &e);
261
+ if (e.is_blocked()) return NSTerminateCancel;
262
+
201
263
  return NSTerminateNow;
202
264
  }
203
265
 
266
+ - (BOOL) isQuitBySystem
267
+ {
268
+ // log out, shut down and restart put a reason on the quit event,
269
+ // while a quit from the dock or a script comes without one
270
+ NSAppleEventDescriptor* event =
271
+ NSAppleEventManager.sharedAppleEventManager.currentAppleEvent;
272
+ return
273
+ event &&
274
+ event.eventClass == kCoreEventClass &&
275
+ event.eventID == kAEQuitApplication &&
276
+ [event attributeDescriptorForKeyword: kAEQuitReason];
277
+ }
278
+
204
279
  - (BOOL) applicationShouldTerminateAfterLastWindowClosed: (NSApplication*) application
205
280
  {
206
- return YES;
281
+ if (Application_should_quit(self->application))
282
+ [self quit];
283
+ return NO;
207
284
  }
208
285
 
209
286
  - (void) applicationWillTerminate: (NSNotification*) notification
210
287
  {
288
+ if (application)
289
+ Application_cleanup(application);
290
+
211
291
  [self unbind];
212
292
  }
213
293