1 2#import "ViewController.h" 3#import "Renderer.h" 4#include "imgui.h" 5 6#if TARGET_OS_OSX 7#include "imgui_impl_osx.h" 8#endif 9 10@interface ViewController () 11@property (nonatomic, readonly) MTKView *mtkView; 12@property (nonatomic, strong) Renderer *renderer; 13@end 14 15@implementation ViewController 16 17- (MTKView *)mtkView { 18 return (MTKView *)self.view; 19} 20 21- (void)viewDidLoad 22{ 23 [super viewDidLoad]; 24 25 self.mtkView.device = MTLCreateSystemDefaultDevice(); 26 27 if (!self.mtkView.device) { 28 NSLog(@"Metal is not supported"); 29 abort(); 30 } 31 32 self.renderer = [[Renderer alloc] initWithView:self.mtkView]; 33 34 [self.renderer mtkView:self.mtkView drawableSizeWillChange:self.mtkView.bounds.size]; 35 36 self.mtkView.delegate = self.renderer; 37 38#if TARGET_OS_OSX 39 // Add a tracking area in order to receive mouse events whenever the mouse is within the bounds of our view 40 NSTrackingArea *trackingArea = [[NSTrackingArea alloc] initWithRect:NSZeroRect 41 options:NSTrackingMouseMoved | NSTrackingInVisibleRect | NSTrackingActiveAlways 42 owner:self 43 userInfo:nil]; 44 [self.view addTrackingArea:trackingArea]; 45 46 // If we want to receive key events, we either need to be in the responder chain of the key view, 47 // or else we can install a local monitor. The consequence of this heavy-handed approach is that 48 // we receive events for all controls, not just Dear ImGui widgets. If we had native controls in our 49 // window, we'd want to be much more careful than just ingesting the complete event stream, though we 50 // do make an effort to be good citizens by passing along events when Dear ImGui doesn't want to capture. 51 NSEventMask eventMask = NSEventMaskKeyDown | NSEventMaskKeyUp | NSEventMaskFlagsChanged | NSEventTypeScrollWheel; 52 [NSEvent addLocalMonitorForEventsMatchingMask:eventMask handler:^NSEvent * _Nullable(NSEvent *event) { 53 BOOL wantsCapture = ImGui_ImplOSX_HandleEvent(event, self.view); 54 if (event.type == NSEventTypeKeyDown && wantsCapture) { 55 return nil; 56 } else { 57 return event; 58 } 59 60 }]; 61 62 ImGui_ImplOSX_Init(); 63#endif 64} 65 66#if TARGET_OS_OSX 67 68- (void)mouseMoved:(NSEvent *)event { 69 ImGui_ImplOSX_HandleEvent(event, self.view); 70} 71 72- (void)mouseDown:(NSEvent *)event { 73 ImGui_ImplOSX_HandleEvent(event, self.view); 74} 75 76- (void)mouseUp:(NSEvent *)event { 77 ImGui_ImplOSX_HandleEvent(event, self.view); 78} 79 80- (void)mouseDragged:(NSEvent *)event { 81 ImGui_ImplOSX_HandleEvent(event, self.view); 82} 83 84- (void)scrollWheel:(NSEvent *)event { 85 ImGui_ImplOSX_HandleEvent(event, self.view); 86} 87 88#elif TARGET_OS_IOS 89 90// This touch mapping is super cheesy/hacky. We treat any touch on the screen 91// as if it were a depressed left mouse button, and we don't bother handling 92// multitouch correctly at all. This causes the "cursor" to behave very erratically 93// when there are multiple active touches. But for demo purposes, single-touch 94// interaction actually works surprisingly well. 95- (void)updateIOWithTouchEvent:(UIEvent *)event { 96 UITouch *anyTouch = event.allTouches.anyObject; 97 CGPoint touchLocation = [anyTouch locationInView:self.view]; 98 ImGuiIO &io = ImGui::GetIO(); 99 io.MousePos = ImVec2(touchLocation.x, touchLocation.y); 100 101 BOOL hasActiveTouch = NO; 102 for (UITouch *touch in event.allTouches) { 103 if (touch.phase != UITouchPhaseEnded && touch.phase != UITouchPhaseCancelled) { 104 hasActiveTouch = YES; 105 break; 106 } 107 } 108 io.MouseDown[0] = hasActiveTouch; 109} 110 111- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { 112 [self updateIOWithTouchEvent:event]; 113} 114 115- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { 116 [self updateIOWithTouchEvent:event]; 117} 118 119- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { 120 [self updateIOWithTouchEvent:event]; 121} 122 123- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { 124 [self updateIOWithTouchEvent:event]; 125} 126 127#endif 128 129@end 130 131