reflexion 0.3.14 → 0.4.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.
data/src/application.cpp CHANGED
@@ -29,12 +29,24 @@ namespace Reflex
29
29
  MIDI_init(app);
30
30
  }
31
31
 
32
+ static void
33
+ close_all_windows (Application* app)
34
+ {
35
+ for (auto it = app->window_begin(), end = app->window_end(); it != end; ++it)
36
+ (*it)->close(true);
37
+ }
38
+
32
39
  void
33
40
  Application_call_quit (Application* app, Event* e)
34
41
  {
42
+ if (app->self->quitting) return;
43
+
35
44
  app->on_quit(e);
36
45
  if (e->is_blocked()) return;
37
46
 
47
+ app->self->quitting = true;
48
+
49
+ close_all_windows(app);
38
50
  MIDI_fin(app);
39
51
  Gamepad_fin(app);
40
52
  }
data/src/application.h CHANGED
@@ -16,6 +16,8 @@ namespace Reflex
16
16
 
17
17
  String name;
18
18
 
19
+ bool quitting = false;
20
+
19
21
  };// Application::Data
20
22
 
21
23
 
data/src/ios/event.h CHANGED
@@ -4,7 +4,7 @@
4
4
  #define __REFLEX_SRC_IOS_EVENT_H__
5
5
 
6
6
 
7
- #import <UIKit/UIEvent.h>
7
+ #import <UIKit/UIKit.h>
8
8
  #include "../event.h"
9
9
 
10
10
 
@@ -12,6 +12,17 @@ namespace Reflex
12
12
  {
13
13
 
14
14
 
15
+ class NativeKeyEvent : public KeyEvent
16
+ {
17
+
18
+ public:
19
+
20
+ NativeKeyEvent (UIPress* press, Action action)
21
+ API_AVAILABLE(ios(13.4));
22
+
23
+ };// NativeKeyEvent
24
+
25
+
15
26
  class NativePointerEvent : public PointerEvent
16
27
  {
17
28
 
@@ -19,9 +30,22 @@ namespace Reflex
19
30
 
20
31
  NativePointerEvent (NSSet* touches, UIEvent* event, UIView* view);
21
32
 
33
+ NativePointerEvent (UIHoverGestureRecognizer* recognizer, UIView* view);
34
+
22
35
  };// NativePointerEvent
23
36
 
24
37
 
38
+ class NativeWheelEvent : public WheelEvent
39
+ {
40
+
41
+ public:
42
+
43
+ NativeWheelEvent (
44
+ UIPanGestureRecognizer* recognizer, UIView* view, CGPoint position);
45
+
46
+ };// NativeWheelEvent
47
+
48
+
25
49
  }// Reflex
26
50
 
27
51
 
data/src/ios/event.mm CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
 
5
5
  #include <assert.h>
6
+ #include <xot/util.h>
6
7
  #include "window.h"
7
8
 
8
9
 
@@ -11,7 +12,23 @@ namespace Reflex
11
12
 
12
13
 
13
14
  static uint
14
- get_type (UITouch* touch)
15
+ get_mouse_button_types (UIEvent* event)
16
+ {
17
+ if (!event) return 0;
18
+
19
+ uint ret = 0;
20
+ if (@available(iOS 13.4, *))
21
+ {
22
+ UIEventButtonMask mask = event.buttonMask;
23
+ if (mask & UIEventButtonMaskPrimary) ret |= Pointer::MOUSE_LEFT;
24
+ if (mask & UIEventButtonMaskSecondary) ret |= Pointer::MOUSE_RIGHT;
25
+ if (mask & UIEventButtonMaskForButtonNumber(3)) ret |= Pointer::MOUSE_MIDDLE;
26
+ }
27
+ return ret;
28
+ }
29
+
30
+ static uint
31
+ get_type (UITouch* touch, UIEvent* event)
15
32
  {
16
33
  assert(touch);
17
34
 
@@ -22,8 +39,15 @@ namespace Reflex
22
39
  {
23
40
  case UITouchTypeDirect: return Pointer::TOUCH;
24
41
  case UITouchTypePencil: return Pointer::PEN;
25
- default: return Pointer::TYPE_NONE;
26
42
  }
43
+
44
+ if (@available(iOS 13.4, *))
45
+ {
46
+ if (type == UITouchTypeIndirectPointer)
47
+ return Pointer::MOUSE | get_mouse_button_types(event);
48
+ }
49
+
50
+ return Pointer::TYPE_NONE;
27
51
  }
28
52
 
29
53
  static Pointer::Action
@@ -52,14 +76,8 @@ namespace Reflex
52
76
  }
53
77
 
54
78
  static uint
55
- get_modifiers (const UIEvent* event)
79
+ to_modifiers (NSInteger flags)
56
80
  {
57
- if (!event) return 0;
58
-
59
- NSInteger flags = 0;
60
- if (@available(iOS 13.4, *))
61
- flags = event.modifierFlags;
62
-
63
81
  return
64
82
  (flags & UIKeyModifierAlphaShift) ? MOD_CAPS : 0 |
65
83
  (flags & UIKeyModifierShift) ? MOD_SHIFT : 0 |
@@ -69,6 +87,18 @@ namespace Reflex
69
87
  (flags & UIKeyModifierNumericPad) ? MOD_NUMPAD : 0;
70
88
  }
71
89
 
90
+ static uint
91
+ get_modifiers (const UIEvent* event)
92
+ {
93
+ if (!event) return 0;
94
+
95
+ NSInteger flags = 0;
96
+ if (@available(iOS 13.4, *))
97
+ flags = event.modifierFlags;
98
+
99
+ return to_modifiers(flags);
100
+ }
101
+
72
102
  uint
73
103
  KeyEvent_get_modifiers ()
74
104
  {
@@ -76,25 +106,45 @@ namespace Reflex
76
106
  }
77
107
 
78
108
 
109
+ static const char*
110
+ get_chars (UIKey* key) API_AVAILABLE(ios(13.4))
111
+ {
112
+ NSString* s = key.characters;
113
+ if (!s || [s hasPrefix: @"UIKeyInput"])
114
+ return NULL;
115
+ return s.UTF8String;
116
+ }
117
+
118
+ NativeKeyEvent::NativeKeyEvent (UIPress* press, Action action)
119
+ : KeyEvent(
120
+ action, get_chars(press.key), (int) press.key.keyCode,
121
+ to_modifiers(press.key.modifierFlags), 0)
122
+ {
123
+ }
124
+
125
+
79
126
  NativePointerEvent::NativePointerEvent (
80
127
  NSSet* touches, UIEvent* event, UIView* view)
81
128
  {
82
129
  for (UITouch* touch in touches)
83
130
  {
84
131
  Pointer::Action action = get_action(touch);
132
+ uint type = get_type(touch, event);
85
133
 
86
134
  Pointer pointer(
87
135
  0,
88
- get_type(touch),
136
+ type,
89
137
  action,
90
138
  to_point([touch locationInView: view]),
91
139
  get_modifiers(event),
92
140
  (uint) touch.tapCount,
93
141
  action == Pointer::MOVE,
94
142
  touch.timestamp);
95
- Pointer_set_system_id(&pointer, (Pointer::ID) touch);
96
143
 
97
- if (pointer.action() != Pointer::DOWN)
144
+ if (!(type & Pointer::MOUSE))
145
+ Pointer_set_system_id(&pointer, (Pointer::ID) touch);
146
+
147
+ if (action != Pointer::DOWN)
98
148
  {
99
149
  Pointer_set_prev_position(
100
150
  &pointer, to_point([touch previousLocationInView: view]));
@@ -105,5 +155,38 @@ namespace Reflex
105
155
  }
106
156
  }
107
157
 
158
+ NativePointerEvent::NativePointerEvent (
159
+ UIHoverGestureRecognizer* recognizer, UIView* view)
160
+ {
161
+ assert(recognizer && view);
162
+
163
+ Pointer pointer(
164
+ 0,
165
+ Pointer::MOUSE,
166
+ Pointer::MOVE,
167
+ to_point([recognizer locationInView: view]),
168
+ get_modifiers(nil),
169
+ 0,
170
+ false,
171
+ Xot::time());
172
+
173
+ if (pointer)
174
+ PointerEvent_add_pointer(this, pointer);
175
+ }
176
+
177
+
178
+ NativeWheelEvent::NativeWheelEvent (
179
+ UIPanGestureRecognizer* recognizer, UIView* view, CGPoint position)
180
+ : WheelEvent(0, 0, 0, 0, 0, 0, get_modifiers(nil))
181
+ {
182
+ assert(recognizer && view);
183
+
184
+ WheelEvent_set_position(this, to_point(position));
185
+
186
+ CGPoint delta = [recognizer translationInView: view];
187
+ this->dposition().x = delta.x;
188
+ this->dposition().y = delta.y;
189
+ }
190
+
108
191
 
109
192
  }// Reflex
@@ -121,12 +121,14 @@ ReflexViewController_get_show_fun ()
121
121
  @end
122
122
 
123
123
 
124
- @interface ReflexViewController () <GLKViewDelegate>
124
+ @interface ReflexViewController () <GLKViewDelegate, UIGestureRecognizerDelegate>
125
125
 
126
126
  @property(nonatomic, strong) ReflexView* reflexView;
127
127
 
128
128
  @property(nonatomic, strong) CADisplayLink* displayLink;
129
129
 
130
+ @property(nonatomic, strong) UIHoverGestureRecognizer* hoverRecognizer;
131
+
130
132
  @end
131
133
 
132
134
 
@@ -264,10 +266,36 @@ ReflexViewController_get_show_fun ()
264
266
  //view.drawableMultisample = GLKViewDrawableMultisample4X;
265
267
 
266
268
  [self.view addSubview: view];
269
+ [self setupMouseRecognizers: view];
267
270
 
268
271
  self.reflexView = view;
269
272
  }
270
273
 
274
+ - (void) setupMouseRecognizers: (UIView*) view
275
+ {
276
+ if (@available(iOS 13.4, *))
277
+ {
278
+ UIHoverGestureRecognizer* hover = [[[UIHoverGestureRecognizer alloc]
279
+ initWithTarget: self action: @selector(hoverChanged:)]
280
+ autorelease];
281
+ hover.delegate = self;
282
+ [view addGestureRecognizer: hover];
283
+ self.hoverRecognizer = hover;
284
+
285
+ UIPanGestureRecognizer* pan = [[[UIPanGestureRecognizer alloc]
286
+ initWithTarget: self action: @selector(scrollChanged:)]
287
+ autorelease];
288
+ pan.allowedScrollTypesMask = UIScrollTypeMaskAll;
289
+ // 0/0 touches means the recognizer only fires from indirect scroll
290
+ // (mouse wheel / trackpad scroll) — touch-based panning is left to
291
+ // the touchesBegan/etc. path so this won't intercept finger pans.
292
+ pan.minimumNumberOfTouches = 0;
293
+ pan.maximumNumberOfTouches = 0;
294
+ pan.delegate = self;
295
+ [view addGestureRecognizer: pan];
296
+ }
297
+ }
298
+
271
299
  - (void) cleanupReflexView
272
300
  {
273
301
  ReflexView* view = self.reflexView;
@@ -299,10 +327,14 @@ ReflexViewController_get_show_fun ()
299
327
  selector: @selector(willResignActive)
300
328
  name: UIApplicationWillResignActiveNotification
301
329
  object: nil];
330
+
331
+ [self becomeFirstResponder];
302
332
  }
303
333
 
304
334
  - (void) viewDidDisappear: (BOOL) animated
305
335
  {
336
+ [self resignFirstResponder];
337
+
306
338
  [NSNotificationCenter.defaultCenter
307
339
  removeObserver: self
308
340
  name: UIApplicationDidBecomeActiveNotification
@@ -334,6 +366,11 @@ ReflexViewController_get_show_fun ()
334
366
  self.reflexView.frame = self.view.bounds;
335
367
  }
336
368
 
369
+ - (BOOL) canBecomeFirstResponder
370
+ {
371
+ return YES;
372
+ }
373
+
337
374
  - (void) startTimer
338
375
  {
339
376
  [self startTimer: 60];
@@ -509,4 +546,99 @@ ReflexViewController_get_show_fun ()
509
546
  Window_call_pointer_event(win, &e);
510
547
  }
511
548
 
549
+ - (void) hoverChanged: (UIHoverGestureRecognizer*) recognizer
550
+ API_AVAILABLE(ios(13.4))
551
+ {
552
+ Reflex::Window* win = self.window;
553
+ if (!win) return;
554
+
555
+ if (touching_count > 0) return;
556
+
557
+ if (
558
+ recognizer.state != UIGestureRecognizerStateBegan &&
559
+ recognizer.state != UIGestureRecognizerStateChanged)
560
+ {
561
+ return;
562
+ }
563
+
564
+ Reflex::NativePointerEvent e(recognizer, self.reflexView);
565
+ if (e.size() > 0)
566
+ Window_call_pointer_event(win, &e);
567
+ }
568
+
569
+ - (void) scrollChanged: (UIPanGestureRecognizer*) recognizer
570
+ API_AVAILABLE(ios(13.4))
571
+ {
572
+ Reflex::Window* win = self.window;
573
+ if (!win) return;
574
+
575
+ if (
576
+ recognizer.state != UIGestureRecognizerStateBegan &&
577
+ recognizer.state != UIGestureRecognizerStateChanged)
578
+ {
579
+ return;
580
+ }
581
+
582
+ // The pan recognizer's locationInView drifts with the synthetic scroll
583
+ // touch, so use the hover recognizer's location — it tracks the actual
584
+ // cursor and exposes the last known position regardless of its state.
585
+ CGPoint pos = [self.hoverRecognizer locationInView: self.reflexView];
586
+
587
+ Reflex::NativeWheelEvent e(recognizer, self.reflexView, pos);
588
+ Window_call_wheel_event(win, &e);
589
+
590
+ // reset translation so subsequent deltas are incremental
591
+ [recognizer setTranslation: CGPointZero inView: self.reflexView];
592
+ }
593
+
594
+ - (BOOL) gestureRecognizer: (UIGestureRecognizer*) recognizer
595
+ shouldRecognizeSimultaneouslyWithGestureRecognizer: (UIGestureRecognizer*) other
596
+ {
597
+ // UIKit only calls this delegate method when at least one of the two
598
+ // recognizers has us set as its delegate, and we only set ourselves as
599
+ // the delegate for our mouse recognizers (hover / indirect scroll). So
600
+ // every call here already involves one of ours, and we want it to run
601
+ // alongside whatever else is on the view (touches, app-added gestures).
602
+ return YES;
603
+ }
604
+
605
+ - (void) pressesBegan: (NSSet<UIPress*>*) presses
606
+ withEvent: (UIPressesEvent*) event
607
+ {
608
+ if (@available(iOS 13.4, *))
609
+ [self handlePresses: presses action: Reflex::KeyEvent::DOWN];
610
+ [super pressesBegan: presses withEvent: event];
611
+ }
612
+
613
+ - (void) pressesEnded: (NSSet<UIPress*>*) presses
614
+ withEvent: (UIPressesEvent*) event
615
+ {
616
+ if (@available(iOS 13.4, *))
617
+ [self handlePresses: presses action: Reflex::KeyEvent::UP];
618
+ [super pressesEnded: presses withEvent: event];
619
+ }
620
+
621
+ - (void) pressesCancelled: (NSSet<UIPress*>*) presses
622
+ withEvent: (UIPressesEvent*) event
623
+ {
624
+ if (@available(iOS 13.4, *))
625
+ [self handlePresses: presses action: Reflex::KeyEvent::UP];
626
+ [super pressesCancelled: presses withEvent: event];
627
+ }
628
+
629
+ - (void) handlePresses: (NSSet<UIPress*>*) presses
630
+ action: (Reflex::KeyEvent::Action) action
631
+ API_AVAILABLE(ios(13.4))
632
+ {
633
+ Reflex::Window* win = self.window;
634
+ if (!win) return;
635
+
636
+ for (UIPress* press in presses)
637
+ {
638
+ if (!press.key) continue;
639
+ Reflex::NativeKeyEvent e(press, action);
640
+ Window_call_key_event(win, &e);
641
+ }
642
+ }
643
+
512
644
  @end// ReflexViewController
data/src/midi.cpp CHANGED
@@ -304,6 +304,10 @@ namespace Reflex
304
304
  void
305
305
  MIDI_init (Application* app)
306
306
  {
307
+ #ifdef WASM
308
+ return;
309
+ #endif
310
+
307
311
  if (manager)
308
312
  invalid_state_error(__FILE__, __LINE__);
309
313
 
data/src/osx/device.mm CHANGED
@@ -9,11 +9,14 @@ namespace Reflex
9
9
  {
10
10
 
11
11
 
12
+ #pragma GCC diagnostic push
13
+ #pragma GCC diagnostic ignored "-Wmissing-noreturn"
12
14
  void
13
15
  vibrate ()
14
16
  {
15
17
  not_implemented_error(__FILE__, __LINE__);
16
18
  }
19
+ #pragma GCC diagnostic pop
17
20
 
18
21
 
19
22
  }// Reflex
data/src/osx/event.mm CHANGED
@@ -163,7 +163,7 @@ namespace Reflex
163
163
 
164
164
 
165
165
  NativeWheelEvent::NativeWheelEvent (NSEvent* e, NSView* view)
166
- : WheelEvent(0, 0, 0, [e deltaX], [e deltaY], [e deltaZ], get_modifiers(e))
166
+ : WheelEvent(0, 0, 0, [e deltaX], -[e deltaY], [e deltaZ], get_modifiers(e))
167
167
  {
168
168
  WheelEvent_set_position(this, get_pointer_position(e, view));
169
169
  }
@@ -2,6 +2,9 @@
2
2
 
3
3
 
4
4
  #include <SDL.h>
5
+ #ifdef WASM
6
+ #include <emscripten.h>
7
+ #endif
5
8
  #include <xot/time.h>
6
9
  #include "reflex/exception.h"
7
10
  #include "reflex/debug.h"
@@ -51,8 +54,8 @@ namespace Reflex
51
54
  return Window_dispatch_event(win, event);
52
55
  }
53
56
 
54
- static bool
55
- dispatch_events ()
57
+ static void
58
+ dispatch_events (Application* app)
56
59
  {
57
60
  SDL_Event event;
58
61
  while (SDL_PollEvent(&event))
@@ -60,13 +63,9 @@ namespace Reflex
60
63
  if (dispatch_window_event(event))
61
64
  continue;
62
65
 
63
- switch (event.type)
64
- {
65
- case SDL_QUIT: return false;
66
- }
66
+ if (event.type == SDL_QUIT)
67
+ app->quit();
67
68
  }
68
-
69
- return true;
70
69
  }
71
70
 
72
71
  static void
@@ -76,18 +75,15 @@ namespace Reflex
76
75
  Window_update(it->get());
77
76
  }
78
77
 
79
- void
80
- Application::start ()
78
+ static void
79
+ main_loop (Application* app)
81
80
  {
82
- Event e;
83
- Application_call_start(this, &e);
84
-
85
- ApplicationData* self = get_data(this);
81
+ ApplicationData* self = get_data(app);
86
82
 
87
83
  double prev = Xot::time();
88
84
  while (!self->quit)
89
85
  {
90
- if (!dispatch_events()) break;
86
+ dispatch_events(app);
91
87
 
92
88
  static const double INTERVAL = 1.0 / 60.0;
93
89
  static const double SLEEPABLE = INTERVAL * 0.9;
@@ -100,11 +96,39 @@ namespace Reflex
100
96
  continue;
101
97
  }
102
98
 
103
- update_all_windows(this);
99
+ update_all_windows(app);
104
100
  prev = now;
105
101
  }
106
102
  }
107
103
 
104
+ #ifdef WASM
105
+ static void
106
+ emscripten_main_loop (void* arg)
107
+ {
108
+ Application* app = (Application*) arg;
109
+
110
+ dispatch_events(app);
111
+
112
+ if (get_data(app)->quit)
113
+ emscripten_cancel_main_loop();
114
+ else
115
+ update_all_windows(app);
116
+ }
117
+ #endif
118
+
119
+ void
120
+ Application::start ()
121
+ {
122
+ Event e;
123
+ Application_call_start(this, &e);
124
+
125
+ #ifdef WASM
126
+ emscripten_set_main_loop_arg(emscripten_main_loop, this, 0, true);
127
+ #else
128
+ main_loop(this);
129
+ #endif
130
+ }
131
+
108
132
  void
109
133
  Application::quit ()
110
134
  {