#import "ViewController.h" #import "Renderer.h" #include "imgui.h" #if TARGET_OS_OSX #include "imgui_impl_osx.h" #endif @interface ViewController () @property (nonatomic, readonly) MTKView *mtkView; @property (nonatomic, strong) Renderer *renderer; @end @implementation ViewController - (MTKView *)mtkView { return (MTKView *)self.view; } - (void)viewDidLoad { [super viewDidLoad]; self.mtkView.device = MTLCreateSystemDefaultDevice(); if (!self.mtkView.device) { NSLog(@"Metal is not supported"); abort(); } self.renderer = [[Renderer alloc] initWithView:self.mtkView]; [self.renderer mtkView:self.mtkView drawableSizeWillChange:self.mtkView.bounds.size]; self.mtkView.delegate = self.renderer; #if TARGET_OS_OSX // Add a tracking area in order to receive mouse events whenever the mouse is within the bounds of our view NSTrackingArea *trackingArea = [[NSTrackingArea alloc] initWithRect:NSZeroRect options:NSTrackingMouseMoved | NSTrackingInVisibleRect | NSTrackingActiveAlways owner:self userInfo:nil]; [self.view addTrackingArea:trackingArea]; // If we want to receive key events, we either need to be in the responder chain of the key view, // or else we can install a local monitor. The consequence of this heavy-handed approach is that // we receive events for all controls, not just Dear ImGui widgets. If we had native controls in our // window, we'd want to be much more careful than just ingesting the complete event stream, though we // do make an effort to be good citizens by passing along events when Dear ImGui doesn't want to capture. NSEventMask eventMask = NSEventMaskKeyDown | NSEventMaskKeyUp | NSEventMaskFlagsChanged | NSEventTypeScrollWheel; [NSEvent addLocalMonitorForEventsMatchingMask:eventMask handler:^NSEvent * _Nullable(NSEvent *event) { BOOL wantsCapture = ImGui_ImplOSX_HandleEvent(event, self.view); if (event.type == NSEventTypeKeyDown && wantsCapture) { return nil; } else { return event; } }]; ImGui_ImplOSX_Init(); #endif } #if TARGET_OS_OSX - (void)mouseMoved:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self.view); } - (void)mouseDown:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self.view); } - (void)mouseUp:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self.view); } - (void)mouseDragged:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self.view); } - (void)scrollWheel:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self.view); } #elif TARGET_OS_IOS // This touch mapping is super cheesy/hacky. We treat any touch on the screen // as if it were a depressed left mouse button, and we don't bother handling // multitouch correctly at all. This causes the "cursor" to behave very erratically // when there are multiple active touches. But for demo purposes, single-touch // interaction actually works surprisingly well. - (void)updateIOWithTouchEvent:(UIEvent *)event { UITouch *anyTouch = event.allTouches.anyObject; CGPoint touchLocation = [anyTouch locationInView:self.view]; ImGuiIO &io = ImGui::GetIO(); io.MousePos = ImVec2(touchLocation.x, touchLocation.y); BOOL hasActiveTouch = NO; for (UITouch *touch in event.allTouches) { if (touch.phase != UITouchPhaseEnded && touch.phase != UITouchPhaseCancelled) { hasActiveTouch = YES; break; } } io.MouseDown[0] = hasActiveTouch; } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [self updateIOWithTouchEvent:event]; } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { [self updateIOWithTouchEvent:event]; } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { [self updateIOWithTouchEvent:event]; } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { [self updateIOWithTouchEvent:event]; } #endif @end