1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

NSViewComponentPeer: Tidying

This commit is contained in:
reuk 2022-06-30 17:04:02 +01:00
parent 4e09161986
commit 31e917ca62
No known key found for this signature in database
GPG key ID: FCB43929F012EE5C
2 changed files with 344 additions and 413 deletions

View file

@ -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 <typename Fn>
void addMethod (SEL selector, Fn callbackFn) { addMethod (selector, detail::toFnPtr (callbackFn)); }

View file

@ -1935,85 +1935,331 @@ struct JuceNSViewClass : public NSViewComponentPeerWrapper<ObjCClass<NSView>>
{
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<void> (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<NSView*> (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<void> (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<void> (self, @selector (keyDown:), ev);
}
});
addMethod (@selector (keyUp:), [] (id self, SEL, NSEvent* ev)
{
auto* owner = getOwner (self);
if (! owner->redirectKeyUp (ev))
sendSuperclassMessage<void> (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<int> 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<Component*> (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<NSDraggingInfo>) { return YES; });
addMethod (@selector (performDragOperation:), [] (id self, SEL, id<NSDraggingInfo> sender)
{
auto* owner = getOwner (self);
return owner != nullptr && owner->sendDragCallback (&NSViewComponentPeer::handleDragDrop, sender);
});
addMethod (@selector (concludeDragOperation:), [] (id, SEL, id<NSDraggingInfo>) {});
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<id> (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<BOOL> (self, s, event);
});
addProtocol (@protocol (NSTextInput));
@ -2028,6 +2274,35 @@ private:
resetTrackingArea (static_cast<NSView*> (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<NSViewComponentPeer*> (focused->getPeer()))
{
return [e type] == NSEventTypeKeyDown ? peer->redirectKeyDown (e)
: peer->redirectKeyUp (e);
}
}
return false;
}
template <typename Func, typename... Args>
static void callOnOwner (id self, Func&& func, Args&&... args)
{
if (auto* owner = getOwner (self))
(owner->*func) (std::forward<Args> (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<NSDraggingInfo> 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<void> (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<void> (self, @selector (keyDown:), ev);
}
}
static void keyUp (id self, SEL, NSEvent* ev)
{
auto* owner = getOwner (self);
if (! owner->redirectKeyUp (ev))
sendSuperclassMessage<void> (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<int> 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<Component*> (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<NSDraggingInfo> sender)
{
return draggingUpdated (self, s, sender);
}
static NSDragOperation draggingUpdated (id self, SEL, id<NSDraggingInfo> sender)
{
if (auto* owner = getOwner (self))
@ -2328,97 +2346,10 @@ private:
return NSDragOperationNone;
}
static void draggingEnded (id self, SEL s, id<NSDraggingInfo> sender)
{
draggingExited (self, s, sender);
}
static void draggingExited (id self, SEL, id<NSDraggingInfo> sender)
{
callOnOwner (self, &NSViewComponentPeer::sendDragCallback, &NSViewComponentPeer::handleDragExit, sender);
}
static BOOL prepareForDragOperation (id, SEL, id<NSDraggingInfo>)
{
return YES;
}
static BOOL performDragOperation (id self, SEL, id<NSDraggingInfo> sender)
{
auto* owner = getOwner (self);
return owner != nullptr && owner->sendDragCallback (&NSViewComponentPeer::handleDragDrop, sender);
}
static void concludeDragOperation (id, SEL, id<NSDraggingInfo>) {}
//==============================================================================
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<id> (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<NSViewComponentPeer*> (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<BOOL> (self, s, event);
}
template <typename Func, typename... Args>
static void callOnOwner (id self, Func&& func, Args&&... args)
{
if (auto* owner = getOwner (self))
(owner->*func) (std::forward<Args> (args)...);
}
};
//==============================================================================