From 31e917ca6234f045e8619a7da9cff20a4bbf8829 Mon Sep 17 00:00:00 2001 From: reuk Date: Thu, 30 Jun 2022 17:04:02 +0100 Subject: [PATCH] NSViewComponentPeer: Tidying --- .../juce_core/native/juce_mac_ObjCHelpers.h | 2 +- .../native/juce_mac_NSViewComponentPeer.mm | 755 ++++++++---------- 2 files changed, 344 insertions(+), 413 deletions(-) diff --git a/modules/juce_core/native/juce_mac_ObjCHelpers.h b/modules/juce_core/native/juce_mac_ObjCHelpers.h index b477144404..e6f12d2848 100644 --- a/modules/juce_core/native/juce_mac_ObjCHelpers.h +++ b/modules/juce_core/native/juce_mac_ObjCHelpers.h @@ -394,7 +394,7 @@ struct ObjCClass BOOL b = class_addIvar (cls, name, sizeof (Type), (uint8_t) rint (log2 (sizeof (Type))), @encode (Type)); jassert (b); ignoreUnused (b); } - + template void addMethod (SEL selector, Fn callbackFn) { addMethod (selector, detail::toFnPtr (callbackFn)); } diff --git a/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm b/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm index 5d15acf600..69d22675ac 100644 --- a/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm +++ b/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm @@ -1935,85 +1935,331 @@ struct JuceNSViewClass : public NSViewComponentPeerWrapper> { JuceNSViewClass() : NSViewComponentPeerWrapper ("JUCEView_") { - addMethod (@selector (isOpaque), isOpaque); - addMethod (@selector (drawRect:), drawRect); - addMethod (@selector (updateTrackingAreas), updateTrackingAreas); - addMethod (@selector (mouseDown:), mouseDown); - addMethod (@selector (mouseUp:), mouseUp); - addMethod (@selector (mouseDragged:), mouseDragged); - addMethod (@selector (mouseMoved:), mouseMoved); - addMethod (@selector (mouseEntered:), mouseEntered); - addMethod (@selector (mouseExited:), mouseExited); - addMethod (@selector (rightMouseDown:), mouseDown); - addMethod (@selector (rightMouseDragged:), mouseDragged); - addMethod (@selector (rightMouseUp:), mouseUp); - addMethod (@selector (otherMouseDown:), mouseDown); - addMethod (@selector (otherMouseDragged:), mouseDragged); - addMethod (@selector (otherMouseUp:), mouseUp); - addMethod (@selector (scrollWheel:), scrollWheel); - addMethod (@selector (magnifyWithEvent:), magnify); - addMethod (@selector (acceptsFirstMouse:), acceptsFirstMouse); - addMethod (@selector (windowWillMiniaturize:), windowWillMiniaturize); - addMethod (@selector (windowDidDeminiaturize:), windowDidDeminiaturize); - addMethod (@selector (windowDidChangeScreen:), windowDidChangeScreen); - addMethod (@selector (wantsDefaultClipping), wantsDefaultClipping); - addMethod (@selector (worksWhenModal), worksWhenModal); - addMethod (@selector (viewDidMoveToWindow), viewDidMoveToWindow); - addMethod (@selector (viewWillDraw), viewWillDraw); - addMethod (@selector (keyDown:), keyDown); - addMethod (@selector (keyUp:), keyUp); - addMethod (@selector (insertText:), insertText); - addMethod (@selector (doCommandBySelector:), doCommandBySelector); - addMethod (@selector (setMarkedText:selectedRange:), setMarkedText); - addMethod (@selector (unmarkText), unmarkText); - addMethod (@selector (hasMarkedText), hasMarkedText); - addMethod (@selector (conversationIdentifier), conversationIdentifier); - addMethod (@selector (attributedSubstringFromRange:), attributedSubstringFromRange); - addMethod (@selector (markedRange), markedRange); - addMethod (@selector (selectedRange), selectedRange); - addMethod (@selector (firstRectForCharacterRange:), firstRectForCharacterRange); - addMethod (@selector (characterIndexForPoint:), characterIndexForPoint); - addMethod (@selector (validAttributesForMarkedText), validAttributesForMarkedText); - addMethod (@selector (flagsChanged:), flagsChanged); + addMethod (@selector (isOpaque), [] (id self, SEL) + { + auto* owner = getOwner (self); + return owner == nullptr || owner->getComponent().isOpaque(); + }); - addMethod (@selector (becomeFirstResponder), becomeFirstResponder); - addMethod (@selector (resignFirstResponder), resignFirstResponder); - addMethod (@selector (acceptsFirstResponder), acceptsFirstResponder); + addMethod (@selector (updateTrackingAreas), [] (id self, SEL) + { + sendSuperclassMessage (self, @selector (updateTrackingAreas)); - addMethod (@selector (draggingEntered:), draggingEntered); - addMethod (@selector (draggingUpdated:), draggingUpdated); - addMethod (@selector (draggingEnded:), draggingEnded); - addMethod (@selector (draggingExited:), draggingExited); - addMethod (@selector (prepareForDragOperation:), prepareForDragOperation); - addMethod (@selector (performDragOperation:), performDragOperation); - addMethod (@selector (concludeDragOperation:), concludeDragOperation); + resetTrackingArea (static_cast (self)); + }); - addMethod (@selector (paste:), paste); - addMethod (@selector (copy:), copy); - addMethod (@selector (cut:), cut); - addMethod (@selector (selectAll:), selectAll); + addMethod (@selector (becomeFirstResponder), [] (id self, SEL) + { + callOnOwner (self, &NSViewComponentPeer::viewFocusGain); + return YES; + }); - addMethod (@selector (viewWillMoveToWindow:), willMoveToWindow); + addMethod (@selector (resignFirstResponder), [] (id self, SEL) + { + callOnOwner (self, &NSViewComponentPeer::viewFocusLoss); + return YES; + }); - addMethod (@selector (isAccessibilityElement), getIsAccessibilityElement); - addMethod (@selector (accessibilityChildren), getAccessibilityChildren); - addMethod (@selector (accessibilityHitTest:), accessibilityHitTest); - addMethod (@selector (accessibilityFocusedUIElement), getAccessibilityFocusedUIElement); + addMethod (NSViewComponentPeer::dismissModalsSelector, [] (id self, SEL) { callOnOwner (self, &NSViewComponentPeer::dismissModals); }); + addMethod (NSViewComponentPeer::frameChangedSelector, [] (id self, SEL, NSNotification*) { callOnOwner (self, &NSViewComponentPeer::redirectMovedOrResized); }); + addMethod (NSViewComponentPeer::becomeKeySelector, [] (id self, SEL) { callOnOwner (self, &NSViewComponentPeer::becomeKey); }); + addMethod (NSViewComponentPeer::resignKeySelector, [] (id self, SEL) { callOnOwner (self, &NSViewComponentPeer::resignKey); }); - // deprecated methods required for backwards compatibility - addMethod (@selector (accessibilityIsIgnored), getAccessibilityIsIgnored); - addMethod (@selector (accessibilityAttributeValue:), getAccessibilityAttributeValue); + addMethod (@selector (paste:), [] (id self, SEL, NSObject* s) { callOnOwner (self, &NSViewComponentPeer::redirectPaste, s); }); + addMethod (@selector (copy:), [] (id self, SEL, NSObject* s) { callOnOwner (self, &NSViewComponentPeer::redirectCopy, s); }); + addMethod (@selector (cut:), [] (id self, SEL, NSObject* s) { callOnOwner (self, &NSViewComponentPeer::redirectCut, s); }); + addMethod (@selector (selectAll:), [] (id self, SEL, NSObject* s) { callOnOwner (self, &NSViewComponentPeer::redirectSelectAll, s); }); - addMethod (@selector (isFlipped), isFlipped); + addMethod (@selector (viewWillMoveToWindow:), [] (id self, SEL, NSWindow* w) { callOnOwner (self, &NSViewComponentPeer::redirectWillMoveToWindow, w); }); + + addMethod (@selector (drawRect:), [] (id self, SEL, NSRect r) { callOnOwner (self, &NSViewComponentPeer::drawRect, r); }); + addMethod (@selector (viewDidMoveToWindow), [] (id self, SEL) { callOnOwner (self, &NSViewComponentPeer::viewMovedToWindow); }); + addMethod (@selector (flagsChanged:), [] (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectModKeyChange, ev); }); + addMethod (@selector (mouseMoved:), [] (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseMove, ev); }); + addMethod (@selector (mouseEntered:), [] (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseEnter, ev); }); + addMethod (@selector (mouseExited:), [] (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseExit, ev); }); + addMethod (@selector (scrollWheel:), [] (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseWheel, ev); }); + addMethod (@selector (magnifyWithEvent:), [] (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMagnify, ev); }); + + addMethod (@selector (mouseDragged:), mouseDragged); + addMethod (@selector (rightMouseDragged:), mouseDragged); + addMethod (@selector (otherMouseDragged:), mouseDragged); - addMethod (NSViewComponentPeer::dismissModalsSelector, dismissModals); addMethod (NSViewComponentPeer::asyncMouseDownSelector, asyncMouseDown); addMethod (NSViewComponentPeer::asyncMouseUpSelector, asyncMouseUp); - addMethod (NSViewComponentPeer::frameChangedSelector, frameChanged); - addMethod (NSViewComponentPeer::becomeKeySelector, becomeKey); - addMethod (NSViewComponentPeer::resignKeySelector, resignKey); - addMethod (@selector (performKeyEquivalent:), performKeyEquivalent); + addMethod (@selector (mouseDown:), mouseDown); + addMethod (@selector (rightMouseDown:), mouseDown); + addMethod (@selector (otherMouseDown:), mouseDown); + + addMethod (@selector (mouseUp:), mouseUp); + addMethod (@selector (rightMouseUp:), mouseUp); + addMethod (@selector (otherMouseUp:), mouseUp); + + addMethod (@selector (draggingEntered:), draggingUpdated); + addMethod (@selector (draggingUpdated:), draggingUpdated); + + addMethod (@selector (draggingEnded:), draggingExited); + addMethod (@selector (draggingExited:), draggingExited); + + addMethod (@selector (acceptsFirstMouse:), [] (id, SEL, NSEvent*) { return YES; }); + + addMethod (@selector (windowWillMiniaturize:), [] (id self, SEL, NSNotification*) + { + if (auto* p = getOwner (self)) + { + if (p->isAlwaysOnTop) + { + // there is a bug when restoring minimised always on top windows so we need + // to remove this behaviour before minimising and restore it afterwards + p->setAlwaysOnTop (false); + p->wasAlwaysOnTop = true; + } + } + }); + + addMethod (@selector (windowDidDeminiaturize:), [] (id self, SEL, NSNotification*) + { + if (auto* p = getOwner (self)) + { + if (p->wasAlwaysOnTop) + p->setAlwaysOnTop (true); + + p->redirectMovedOrResized(); + } + }); + + addMethod (@selector (windowDidChangeScreen:), [] (id self, SEL, NSNotification*) + { + if (auto* p = getOwner (self)) + p->windowDidChangeScreen(); + }); + + addMethod (@selector (wantsDefaultClipping), [] (id, SEL) { return YES; }); // (this is the default, but may want to customise it in future) + + addMethod (@selector (worksWhenModal), [] (id self, SEL) + { + if (auto* p = getOwner (self)) + return p->worksWhenModal(); + + return false; + }); + + addMethod (@selector (viewWillDraw), [] (id self, SEL) + { + // Without setting contentsFormat macOS Big Sur will always set the invalid area + // to be the entire frame. + #if defined (MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12 + if (@available (macOS 10.12, *)) + { + CALayer* layer = ((NSView*) self).layer; + layer.contentsFormat = kCAContentsFormatRGBA8Uint; + } + #endif + + sendSuperclassMessage (self, @selector (viewWillDraw)); + }); + + addMethod (@selector (keyDown:), [] (id self, SEL, NSEvent* ev) + { + if (auto* owner = getOwner (self)) + { + auto* target = owner->findCurrentTextInputTarget(); + owner->textWasInserted = false; + + if (target != nullptr) + [(NSView*) self interpretKeyEvents: [NSArray arrayWithObject: ev]]; + else + owner->stringBeingComposed.clear(); + + if (! (owner->textWasInserted || owner->redirectKeyDown (ev))) + sendSuperclassMessage (self, @selector (keyDown:), ev); + } + }); + + addMethod (@selector (keyUp:), [] (id self, SEL, NSEvent* ev) + { + auto* owner = getOwner (self); + + if (! owner->redirectKeyUp (ev)) + sendSuperclassMessage (self, @selector (keyUp:), ev); + }); + + addMethod (@selector (insertText:), [] (id self, SEL, id aString) + { + // This commits multi-byte text when return is pressed, or after every keypress for western keyboards + if (auto* owner = getOwner (self)) + { + NSString* newText = [aString isKindOfClass: [NSAttributedString class]] ? [aString string] : aString; + + if ([newText length] > 0) + { + if (auto* target = owner->findCurrentTextInputTarget()) + { + target->insertTextAtCaret (nsStringToJuce (newText)); + owner->textWasInserted = true; + } + } + + owner->stringBeingComposed.clear(); + } + }); + + addMethod (@selector (doCommandBySelector:), [] (id, SEL, SEL) {}); + + addMethod (@selector (setMarkedText:selectedRange:), [] (id self, SEL, id aString, NSRange) + { + if (auto* owner = getOwner (self)) + { + owner->stringBeingComposed = nsStringToJuce ([aString isKindOfClass: [NSAttributedString class]] + ? [aString string] : aString); + + if (auto* target = owner->findCurrentTextInputTarget()) + { + auto currentHighlight = target->getHighlightedRegion(); + target->insertTextAtCaret (owner->stringBeingComposed); + target->setHighlightedRegion (currentHighlight.withLength (owner->stringBeingComposed.length())); + owner->textWasInserted = true; + } + } + }); + + addMethod (@selector (unmarkText), [] (id self, SEL) + { + if (auto* owner = getOwner (self)) + { + if (owner->stringBeingComposed.isNotEmpty()) + { + if (auto* target = owner->findCurrentTextInputTarget()) + { + target->insertTextAtCaret (owner->stringBeingComposed); + owner->textWasInserted = true; + } + + owner->stringBeingComposed.clear(); + } + } + }); + + addMethod (@selector (hasMarkedText), [] (id self, SEL) + { + auto* owner = getOwner (self); + return owner != nullptr && owner->stringBeingComposed.isNotEmpty(); + }); + + addMethod (@selector (conversationIdentifier), [] (id self, SEL) + { + return (long) (pointer_sized_int) self; + }); + + addMethod (@selector (attributedSubstringFromRange:), [] (id self, SEL, NSRange theRange) -> NSAttributedString* + { + if (auto* owner = getOwner (self)) + { + if (auto* target = owner->findCurrentTextInputTarget()) + { + Range r ((int) theRange.location, + (int) (theRange.location + theRange.length)); + + return [[[NSAttributedString alloc] initWithString: juceStringToNS (target->getTextInRange (r))] autorelease]; + } + } + + return nil; + }); + + addMethod (@selector (markedRange), [] (id self, SEL) + { + if (auto* owner = getOwner (self)) + if (owner->stringBeingComposed.isNotEmpty()) + return NSMakeRange (0, (NSUInteger) owner->stringBeingComposed.length()); + + return NSMakeRange (NSNotFound, 0); + }); + + addMethod (@selector (selectedRange), [] (id self, SEL) + { + if (auto* owner = getOwner (self)) + { + if (auto* target = owner->findCurrentTextInputTarget()) + { + auto highlight = target->getHighlightedRegion(); + + if (! highlight.isEmpty()) + return NSMakeRange ((NSUInteger) highlight.getStart(), + (NSUInteger) highlight.getLength()); + } + } + + return NSMakeRange (NSNotFound, 0); + }); + + addMethod (@selector (firstRectForCharacterRange:), [] (id self, SEL, NSRange) + { + if (auto* owner = getOwner (self)) + if (auto* comp = dynamic_cast (owner->findCurrentTextInputTarget())) + return flippedScreenRect (makeNSRect (comp->getScreenBounds())); + + return NSZeroRect; + }); + + addMethod (@selector (characterIndexForPoint:), [] (id, SEL, NSPoint) { return NSNotFound; }); + + addMethod (@selector (validAttributesForMarkedText), [] (id, SEL) { return [NSArray array]; }); + + addMethod (@selector (acceptsFirstResponder), [] (id self, SEL) + { + auto* owner = getOwner (self); + return owner != nullptr && owner->canBecomeKeyWindow(); + }); + + addMethod (@selector (prepareForDragOperation:), [] (id, SEL, id) { return YES; }); + + addMethod (@selector (performDragOperation:), [] (id self, SEL, id sender) + { + auto* owner = getOwner (self); + return owner != nullptr && owner->sendDragCallback (&NSViewComponentPeer::handleDragDrop, sender); + }); + + addMethod (@selector (concludeDragOperation:), [] (id, SEL, id) {}); + + addMethod (@selector (isAccessibilityElement), [] (id, SEL) { return NO; }); + + addMethod (@selector (accessibilityChildren), getAccessibilityChildren); + + addMethod (@selector (accessibilityHitTest:), [] (id self, SEL, NSPoint point) + { + return [getAccessibleChild (self) accessibilityHitTest: point]; + }); + + addMethod (@selector (accessibilityFocusedUIElement), [] (id self, SEL) + { + return [getAccessibleChild (self) accessibilityFocusedUIElement]; + }); + + // deprecated methods required for backwards compatibility + addMethod (@selector (accessibilityIsIgnored), [] (id, SEL) { return YES; }); + + addMethod (@selector (accessibilityAttributeValue:), [] (id self, SEL, NSString* attribute) -> id + { + if ([attribute isEqualToString: NSAccessibilityChildrenAttribute]) + return getAccessibilityChildren (self, {}); + + return sendSuperclassMessage (self, @selector (accessibilityAttributeValue:), attribute); + }); + + addMethod (@selector (isFlipped), [] (id, SEL) { return true; }); + + addMethod (@selector (performKeyEquivalent:), [] (id self, SEL s, NSEvent* event) + { + // We try passing shortcut keys to the currently focused component first. + // If the component doesn't want the event, we'll fall back to the superclass + // implementation, which will pass the event to the main menu. + if (tryPassingKeyEventToPeer (event)) + return YES; + + return sendSuperclassMessage (self, s, event); + }); addProtocol (@protocol (NSTextInput)); @@ -2028,6 +2274,35 @@ private: resetTrackingArea (static_cast (self)); } + static bool tryPassingKeyEventToPeer (NSEvent* e) + { + if ([e type] != NSEventTypeKeyDown && [e type] != NSEventTypeKeyUp) + return false; + + if (auto* focused = Component::getCurrentlyFocusedComponent()) + { + if (auto* peer = dynamic_cast (focused->getPeer())) + { + return [e type] == NSEventTypeKeyDown ? peer->redirectKeyDown (e) + : peer->redirectKeyUp (e); + } + } + + return false; + } + + template + static void callOnOwner (id self, Func&& func, Args&&... args) + { + if (auto* owner = getOwner (self)) + (owner->*func) (std::forward (args)...); + } + + static void mouseDragged (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseDrag, ev); } + static void asyncMouseDown (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseDown, ev); } + static void asyncMouseUp (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseUp, ev); } + static void draggingExited (id self, SEL, id sender) { callOnOwner (self, &NSViewComponentPeer::sendDragCallback, &NSViewComponentPeer::handleDragExit, sender); } + static void mouseDown (id self, SEL s, NSEvent* ev) { if (JUCEApplicationBase::isStandaloneApp()) @@ -2062,263 +2337,6 @@ private: } } - static void asyncMouseDown (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseDown, ev); } - static void asyncMouseUp (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseUp, ev); } - static void mouseDragged (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseDrag, ev); } - static void mouseMoved (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseMove, ev); } - static void mouseEntered (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseEnter, ev); } - static void mouseExited (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseExit, ev); } - static void scrollWheel (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseWheel, ev); } - static void magnify (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMagnify, ev); } - static void copy (id self, SEL, NSObject* s) { callOnOwner (self, &NSViewComponentPeer::redirectCopy, s); } - static void paste (id self, SEL, NSObject* s) { callOnOwner (self, &NSViewComponentPeer::redirectPaste, s); } - static void cut (id self, SEL, NSObject* s) { callOnOwner (self, &NSViewComponentPeer::redirectCut, s); } - static void selectAll (id self, SEL, NSObject* s) { callOnOwner (self, &NSViewComponentPeer::redirectSelectAll, s); } - static void willMoveToWindow (id self, SEL, NSWindow* w) { callOnOwner (self, &NSViewComponentPeer::redirectWillMoveToWindow, w); } - - static BOOL acceptsFirstMouse (id, SEL, NSEvent*) { return YES; } - static BOOL wantsDefaultClipping (id, SEL) { return YES; } // (this is the default, but may want to customise it in future) - static BOOL worksWhenModal (id self, SEL) { if (auto* p = getOwner (self)) return p->worksWhenModal(); return NO; } - - static void drawRect (id self, SEL, NSRect r) { callOnOwner (self, &NSViewComponentPeer::drawRect, r); } - static void frameChanged (id self, SEL, NSNotification*) { callOnOwner (self, &NSViewComponentPeer::redirectMovedOrResized); } - static void viewDidMoveToWindow (id self, SEL) { callOnOwner (self, &NSViewComponentPeer::viewMovedToWindow); } - static void dismissModals (id self, SEL) { callOnOwner (self, &NSViewComponentPeer::dismissModals); } - static void becomeKey (id self, SEL) { callOnOwner (self, &NSViewComponentPeer::becomeKey); } - static void resignKey (id self, SEL) { callOnOwner (self, &NSViewComponentPeer::resignKey); } - - static BOOL isFlipped (id, SEL) { return true; } - - static void viewWillDraw (id self, SEL) - { - // Without setting contentsFormat macOS Big Sur will always set the invalid area - // to be the entire frame. - #if defined (MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12 - if (@available (macOS 10.12, *)) - { - CALayer* layer = ((NSView*) self).layer; - layer.contentsFormat = kCAContentsFormatRGBA8Uint; - } - #endif - - sendSuperclassMessage (self, @selector (viewWillDraw)); - } - - static void windowWillMiniaturize (id self, SEL, NSNotification*) - { - if (auto* p = getOwner (self)) - { - if (p->isAlwaysOnTop) - { - // there is a bug when restoring minimised always on top windows so we need - // to remove this behaviour before minimising and restore it afterwards - p->setAlwaysOnTop (false); - p->wasAlwaysOnTop = true; - } - } - } - - static void windowDidDeminiaturize (id self, SEL, NSNotification*) - { - if (auto* p = getOwner (self)) - { - if (p->wasAlwaysOnTop) - p->setAlwaysOnTop (true); - - p->redirectMovedOrResized(); - } - } - - static void windowDidChangeScreen (id self, SEL, NSNotification*) - { - if (auto* p = getOwner (self)) - p->windowDidChangeScreen(); - } - - static BOOL isOpaque (id self, SEL) - { - auto* owner = getOwner (self); - return owner == nullptr || owner->getComponent().isOpaque(); - } - - //============================================================================== - static void keyDown (id self, SEL, NSEvent* ev) - { - if (auto* owner = getOwner (self)) - { - auto* target = owner->findCurrentTextInputTarget(); - owner->textWasInserted = false; - - if (target != nullptr) - [(NSView*) self interpretKeyEvents: [NSArray arrayWithObject: ev]]; - else - owner->stringBeingComposed.clear(); - - if (! (owner->textWasInserted || owner->redirectKeyDown (ev))) - sendSuperclassMessage (self, @selector (keyDown:), ev); - } - } - - static void keyUp (id self, SEL, NSEvent* ev) - { - auto* owner = getOwner (self); - - if (! owner->redirectKeyUp (ev)) - sendSuperclassMessage (self, @selector (keyUp:), ev); - } - - //============================================================================== - static void insertText (id self, SEL, id aString) - { - // This commits multi-byte text when return is pressed, or after every keypress for western keyboards - if (auto* owner = getOwner (self)) - { - NSString* newText = [aString isKindOfClass: [NSAttributedString class]] ? [aString string] : aString; - - if ([newText length] > 0) - { - if (auto* target = owner->findCurrentTextInputTarget()) - { - target->insertTextAtCaret (nsStringToJuce (newText)); - owner->textWasInserted = true; - } - } - - owner->stringBeingComposed.clear(); - } - } - - static void doCommandBySelector (id, SEL, SEL) {} - - static void setMarkedText (id self, SEL, id aString, NSRange) - { - if (auto* owner = getOwner (self)) - { - owner->stringBeingComposed = nsStringToJuce ([aString isKindOfClass: [NSAttributedString class]] - ? [aString string] : aString); - - if (auto* target = owner->findCurrentTextInputTarget()) - { - auto currentHighlight = target->getHighlightedRegion(); - target->insertTextAtCaret (owner->stringBeingComposed); - target->setHighlightedRegion (currentHighlight.withLength (owner->stringBeingComposed.length())); - owner->textWasInserted = true; - } - } - } - - static void unmarkText (id self, SEL) - { - if (auto* owner = getOwner (self)) - { - if (owner->stringBeingComposed.isNotEmpty()) - { - if (auto* target = owner->findCurrentTextInputTarget()) - { - target->insertTextAtCaret (owner->stringBeingComposed); - owner->textWasInserted = true; - } - - owner->stringBeingComposed.clear(); - } - } - } - - static BOOL hasMarkedText (id self, SEL) - { - auto* owner = getOwner (self); - return owner != nullptr && owner->stringBeingComposed.isNotEmpty(); - } - - static long conversationIdentifier (id self, SEL) - { - return (long) (pointer_sized_int) self; - } - - static NSAttributedString* attributedSubstringFromRange (id self, SEL, NSRange theRange) - { - if (auto* owner = getOwner (self)) - { - if (auto* target = owner->findCurrentTextInputTarget()) - { - Range r ((int) theRange.location, - (int) (theRange.location + theRange.length)); - - return [[[NSAttributedString alloc] initWithString: juceStringToNS (target->getTextInRange (r))] autorelease]; - } - } - - return nil; - } - - static NSRange markedRange (id self, SEL) - { - if (auto* owner = getOwner (self)) - if (owner->stringBeingComposed.isNotEmpty()) - return NSMakeRange (0, (NSUInteger) owner->stringBeingComposed.length()); - - return NSMakeRange (NSNotFound, 0); - } - - static NSRange selectedRange (id self, SEL) - { - if (auto* owner = getOwner (self)) - { - if (auto* target = owner->findCurrentTextInputTarget()) - { - auto highlight = target->getHighlightedRegion(); - - if (! highlight.isEmpty()) - return NSMakeRange ((NSUInteger) highlight.getStart(), - (NSUInteger) highlight.getLength()); - } - } - - return NSMakeRange (NSNotFound, 0); - } - - static NSRect firstRectForCharacterRange (id self, SEL, NSRange) - { - if (auto* owner = getOwner (self)) - if (auto* comp = dynamic_cast (owner->findCurrentTextInputTarget())) - return flippedScreenRect (makeNSRect (comp->getScreenBounds())); - - return NSZeroRect; - } - - static NSUInteger characterIndexForPoint (id, SEL, NSPoint) { return NSNotFound; } - static NSArray* validAttributesForMarkedText (id, SEL) { return [NSArray array]; } - - //============================================================================== - static void flagsChanged (id self, SEL, NSEvent* ev) - { - callOnOwner (self, &NSViewComponentPeer::redirectModKeyChange, ev); - } - - static BOOL becomeFirstResponder (id self, SEL) - { - callOnOwner (self, &NSViewComponentPeer::viewFocusGain); - return YES; - } - - static BOOL resignFirstResponder (id self, SEL) - { - callOnOwner (self, &NSViewComponentPeer::viewFocusLoss); - return YES; - } - - static BOOL acceptsFirstResponder (id self, SEL) - { - auto* owner = getOwner (self); - return owner != nullptr && owner->canBecomeKeyWindow(); - } - - //============================================================================== - static NSDragOperation draggingEntered (id self, SEL s, id sender) - { - return draggingUpdated (self, s, sender); - } - static NSDragOperation draggingUpdated (id self, SEL, id sender) { if (auto* owner = getOwner (self)) @@ -2328,97 +2346,10 @@ private: return NSDragOperationNone; } - static void draggingEnded (id self, SEL s, id sender) - { - draggingExited (self, s, sender); - } - - static void draggingExited (id self, SEL, id sender) - { - callOnOwner (self, &NSViewComponentPeer::sendDragCallback, &NSViewComponentPeer::handleDragExit, sender); - } - - static BOOL prepareForDragOperation (id, SEL, id) - { - return YES; - } - - static BOOL performDragOperation (id self, SEL, id sender) - { - auto* owner = getOwner (self); - return owner != nullptr && owner->sendDragCallback (&NSViewComponentPeer::handleDragDrop, sender); - } - - static void concludeDragOperation (id, SEL, id) {} - - //============================================================================== - static BOOL getIsAccessibilityElement (id, SEL) - { - return NO; - } - static NSArray* getAccessibilityChildren (id self, SEL) { return NSAccessibilityUnignoredChildrenForOnlyChild (getAccessibleChild (self)); } - - static id accessibilityHitTest (id self, SEL, NSPoint point) - { - return [getAccessibleChild (self) accessibilityHitTest: point]; - } - - static id getAccessibilityFocusedUIElement (id self, SEL) - { - return [getAccessibleChild (self) accessibilityFocusedUIElement]; - } - - static BOOL getAccessibilityIsIgnored (id, SEL) - { - return YES; - } - - static id getAccessibilityAttributeValue (id self, SEL, NSString* attribute) - { - if ([attribute isEqualToString: NSAccessibilityChildrenAttribute]) - return getAccessibilityChildren (self, {}); - - return sendSuperclassMessage (self, @selector (accessibilityAttributeValue:), attribute); - } - - static bool tryPassingKeyEventToPeer (NSEvent* e) - { - if ([e type] != NSEventTypeKeyDown && [e type] != NSEventTypeKeyUp) - return false; - - if (auto* focused = Component::getCurrentlyFocusedComponent()) - { - if (auto* peer = dynamic_cast (focused->getPeer())) - { - return [e type] == NSEventTypeKeyDown ? peer->redirectKeyDown (e) - : peer->redirectKeyUp (e); - } - } - - return false; - } - - static BOOL performKeyEquivalent (id self, SEL s, NSEvent* event) - { - // We try passing shortcut keys to the currently focused component first. - // If the component doesn't want the event, we'll fall back to the superclass - // implementation, which will pass the event to the main menu. - if (tryPassingKeyEventToPeer (event)) - return YES; - - return sendSuperclassMessage (self, s, event); - } - - template - static void callOnOwner (id self, Func&& func, Args&&... args) - { - if (auto* owner = getOwner (self)) - (owner->*func) (std::forward (args)...); - } }; //==============================================================================