borderless child NSWindow not getting events - cocoa

I create a NSWindow with this code, but I don't receive any mouse or keyboard events for it:
window = [[OverlayWindow alloc] initWithContentRect:bounds styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
[parentWindow addChildWindow:window ordered:NSWindowAbove];
NSView * rootView = [[OverlayView alloc] init];
[window setOpaque:NO];
[window setBackgroundColor:[NSColor clearColor]];
[window setContentView:rootView];
[window setIgnoresMouseEvents:NO];
[self reshapeToRect:bounds];
and in OverlayWindow:
- (BOOL) canBecomeKeyWindow { return YES; }
- (BOOL) canBecomeMainWindow { return YES; }
- (BOOL) acceptsFirstResponder { return YES; }
- (BOOL) becomeFirstResponder { return YES; }
- (BOOL) resignFirstResponder { return YES; }

[window orderWindow:NSWindowAbove relativeTo:[parentWindow windowNumber]];
did the trick

Related

mouseExited is no longer called after mouseDown in NSButton subclass

In building a custom NSButton, I've run into a problem handling highlight behavior. After clicking down on the button, holding, and dragging the cursor outside the button's bounds, mouseExited: and mouseEntered: events are not delivered. I understand the reason why, because in mouseDown: calling [super mouseDown:event]; will block until the click is released.
In researching this I came across this Stack Overflow post which describes the same problem. The solution noted is to add NSTrackingEnabledDuringMouseDrag to the NSTrackingArea options, which I have done, yet I continue to see this problem. I tried the other proposed solution with handling the next events in a loop, but this resulted in odd behavior. The button text color turns black on mouse down instead of highlighting the dimmed color, and it doesn't unhighlight upon releasing the mouse, it remains black.
I am using Xcode 9.3, running on macOS 10.13.4.
Here is my NSButton subclass:
#interface BorderlessButton : NSButton {
NSColor *_tempColor;
}
#property (strong, nonatomic) NSColor *color;
#end
#interface BorderlessButton ()
#property (nonatomic) BOOL pressed;
#end
#implementation BorderlessButton
- (id)init {
if (self = [super init]) {
[self setUp];
}
return self;
}
- (id)initWithFrame:(NSRect)frameRect {
if (self = [super initWithFrame:frameRect]) {
[self setUp];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
[self setUp];
}
return self;
}
- (void)setUp {
_color = [NSColor redColor];
[self setTitle:self.title];
[self setButtonType:NSButtonTypeMomentaryChange];
[self setBordered:NO];
NSTrackingArea *area = [[NSTrackingArea alloc] initWithRect:self.bounds
options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingEnabledDuringMouseDrag
owner:self
userInfo:nil];
[self addTrackingArea:area];
}
- (void)setTitle:(NSString *)title {
[super setTitle:title];
NSMutableAttributedString *colorTitle = [[NSMutableAttributedString alloc] initWithAttributedString:[self attributedTitle]];
[colorTitle addAttributes:#{NSFontAttributeName: self.font, NSForegroundColorAttributeName: self.color} range:NSMakeRange(0, [colorTitle length])];
[self setAttributedTitle:colorTitle];
}
- (void)setColor:(NSColor *)color {
_color = color;
[self setTitle:self.title];
}
- (void)mouseDown:(NSEvent *)event {
self.pressed = YES;
[self highlight:YES];
[super mouseDown:event]; // this blocks until released
[self mouseUp:event];
}
- (void)mouseUp:(NSEvent *)event {
self.pressed = NO;
[self highlight:NO];
[super mouseUp:event];
}
//FIXME: Not called after mouse press down and hold then exit
- (void)mouseExited:(NSEvent *)event {
if (self.pressed) {
[self highlight:NO];
}
[super mouseExited:event];
}
- (void)mouseEntered:(NSEvent *)event {
if (self.pressed) {
[self highlight:YES];
}
[super mouseEntered:event];
}
- (void)highlight:(BOOL)flag {
if (flag) {
if (self.isEnabled) {
NSColor *dimmedColor = [self dimmedColor];
_tempColor = _color;
self.color = dimmedColor;
[self setTitle:self.title];
}
} else {
if (self.isEnabled) {
self.color = _tempColor;
[self setTitle:self.title];
}
}
}
- (NSColor *)dimmedColor {
return [self.color colorWithAlphaComponent:0.5];
}
#end

NSButton Toggle : OnClick title get removed on OSX 10.11

I am using a Toggle button in XIB,
in AwakeFromNib :I set title and BG image of the button.
Code works very well till OSX 10.10.5 and below but on higher versions when I click on button the text gets removed.
Set attributed Title
[self.deleteButton setWantsLayer:YES];
self.deleteButton.layer.backgroundColor = [self setButtonBGColor];
[self setButtonTitleFor:self.deleteButton
toString:#"Delete"];
[self.deleteButton setLayerContentsRedrawPolicy:NSViewLayerContentsRedrawOnSetNeedsDisplay];
- (void)setButtonTitleFor:(NSButton*)button toString:(NSString*)title
{
NSAttributedString *attrString = [self getAttributedStringForString:title];
[button setAttributedTitle:attrString];
}
Any idea hat should be done.
So finally got it right
Subclassing NSButtonCell helped me out
RPButtonTextTopCell.h
#interface RPButtonTextTopCell : NSButtonCell
#end
RPButtonTextTopCell.m
#implementation RPButtonTextTopCell
-(id) init
{
self = [super init];
if (self) {
}
return self;
}
-(id) initWithCoder:(NSCoder *)decoder
{
return [super initWithCoder:decoder];
}
-(id) initTextCell:(NSString *)string
{
return [super initTextCell:string];
}
-(NSRect)titleRectForBounds:(NSRect)theRect
{
NSRect titleFrame = [super titleRectForBounds:theRect];
NSSize titleSize = [[self attributedStringValue] size];
titleFrame.origin.y = (theRect.origin.y - (theRect.size.height-titleSize.height)*0.5) + 5;
return titleFrame;
}
#end
Utilizing This Custom Class
RPButtonTextTopCell *deleteCell = [[RPButtonTextTopCell alloc] init];
deleteCell.backgroundColor = [self setNSButtonBGColor];
[self.deleteButton setCell:deleteCell];
[self setButtonTitleFor:self.deleteButton
toString:#"Delete"];
[self.deleteButton setAction:#selector(deleteButtonClicked:)];
[self.deleteButton setTarget:self];
and its solved....

Subviews out of bounds of NSScrollView respond to mouse event

My problem is that the subviews of my scrollView respond to mouse event even if they are not visible (out of the bounds of the visible part of the scrollView).
I've got this architecture :
CustomView *view01 = [[CustomView alloc] init];
CustomView *view02 = [[CustomView alloc] init];
NSView *contentView = [[NSView alloc] init];
[contentView addSubview:view01];
[contentView addSubview:view02];
NSSCrollView *scrollView = [[NSScrollView alloc] init];
scrollView setDocumentView:contentView];
With the CustomView implementation :
#import "CustomView.h"
#interface CustomView ()
{
NSTrackingArea *trackingArea;
}
#end
#implementation CustomView
-(id)initWithFrame:(NSRect)contentRect
{
if(self = [super initWithFrame:(NSRect)contentRect])
{
[self setFrame:contentRect];
}
return self;
}
- (void)mouseDown: (NSEvent*)event
{
NSLog(#"mouseDown:");
[NSApp preventWindowOrdering];
}
- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)evt
{
return YES;
}
-(BOOL)acceptsFirstResponder
{
return YES;
}
-(void)updateTrackingAreas
{
if(trackingArea != nil)
{
[self removeTrackingArea:trackingArea];
}
int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways);
trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds]
options:opts
owner:self
userInfo:nil];
[self addTrackingArea:trackingArea];
}
- (void)mouseEntered:(NSEvent *)theEvent
{
NSLog(#"mouseEntered:");
}
- (void)mouseExited:(NSEvent *)theEvent
{
NSLog(#"mouseExited:");
}
- (NSView *)hitTest:(NSPoint)aPoint
{
return NSPointInRect(aPoint, self.frame) ? self : nil;
}
#end
I finally found the problem.
I needed to add the option NSTrackingInVisibleRect in the method :
-(void)updateTrackingAreas
{
if(trackingArea != nil)
{
[self removeTrackingArea:trackingArea];
}
int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways| NSTrackingInVisibleRect);
trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds]
options:opts
owner:self
userInfo:nil];
[self addTrackingArea:trackingArea];
}
Then, when a part of the CustomView are outside the scrollView, it doesn't respond to mouseEntered and mouseExited.

traffic buttons not responding in MacOS application

I am creating an application on MacOS and I am having this problem. I am using custom traffic buttons. When the window is not active if I click they do not respond, what I get is the window becoming active.
How could I fix that so the buttons will respond even if the window is not the active one.
I have them added to a custom view, here is what I have:
My View:
#implementation TrafficView
- (id)init {
if ((self = [super init])) {
trackingArea_.reset([[NSTrackingArea alloc]
initWithRect:[self bounds]
options:(NSTrackingMouseEnteredAndExited |
NSTrackingActiveAlways |
NSTrackingInVisibleRect)
owner:self
userInfo:nil]);
[self addTrackingArea:trackingArea_.get()];
}
return self;
}
- (void)dealloc {
[super dealloc];
}
- (BOOL)acceptsFirstResponder {
return YES;
}
- (BOOL)acceptsFirstMouse:(NSEvent*)theEvent {
return YES;
}
- (void)mouseEntered:(NSEvent*)event {
mouseInside_ = YES;
for (NSView* view in self.subviews)
[view setNeedsDisplay:YES];
}
- (void)mouseExited:(NSEvent*)event {
mouseInside_ = NO;
for (NSView* view in self.subviews)
[view setNeedsDisplay:YES];
}
- (BOOL)_mouseInGroup:(NSButton *)button {
return mouseInside_;
}
#end
Now to add the buttons I do this in the window implementation (I will post the code for only one button)
trafficView_.reset([[TrafficView alloc] init]);
[self.frameView addSubview:trafficView_];
// close button is declared as NSButton
closeButton_ =
[NSWindow standardWindowButton:NSWindowCloseButton
forStyleMask:NSTitledWindowMask];
[trafficView_ addSubview:closeButton_];
Note that my custom view (trafficView_) is added to the NSThemeFrame class, self.frameView
- (NSView*)frameView {
return [[self contentView] superview];
}
I do not why the buttons do not respond.
Could someone help on this?
Thanks in advance

How to call registerForDraggedTypes in NSViewController?

I have a MainViewController with a splitview in it. Next I have two viewcontroller to control each of the views in the splitview. I want to be able to drag and drop a file in one of those views.
But I can't seem to get the dragging to work? There's no "plus-sign" on the file when dragged to the view and dropping it doesn't do anything either.
What am I doing wrong?
First here's MainViewController.m
fileViewController = [[FileViewController alloc] initWithNibName:#"FileViewController" bundle:nil];
terminalViewController = [[TerminalViewController alloc] initWithNibName:#"TerminalViewController" bundle:nil];
[splitView replaceSubview:[[splitView subviews] objectAtIndex:0] with:[fileViewController view]];
[splitView replaceSubview:[[splitView subviews] objectAtIndex:1] with:[terminalViewController view]];
Next, my code to handle the dragging in the FileViewController
#dynamic isHighlighted;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
NSLog(#"registering");
[self.view registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
}
return self;
}
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender {
NSLog(#"[%# %#]", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
NSPasteboard *pboard = [sender draggingPasteboard];
if ([[pboard types] containsObject:NSFilenamesPboardType]) {
NSArray *paths = [pboard propertyListForType:NSFilenamesPboardType];
for (NSString *path in paths) {
NSError *error = nil;
NSString *utiType = [[NSWorkspace sharedWorkspace]
typeOfFile:path error:&error];
if (![[NSWorkspace sharedWorkspace]
type:utiType conformsToType:(id)kUTTypeFolder]) {
[self setHighlighted:NO];
return NSDragOperationNone;
}
}
}
[self setHighlighted:YES];
return NSDragOperationEvery;
}
- (void)draggingExited:(id <NSDraggingInfo>)sender {
[self setHighlighted:NO];
}
- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender {
return YES;
}
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender {
[self setHighlighted:NO];
return YES;
}
- (void)concludeDragOperation:(id )sender {
[self.view setNeedsDisplay:YES];
} // end concludeDragOperation
- (BOOL)isHighlighted {
return isHighlighted;
}
- (void)setHighlighted:(BOOL)value {
isHighlighted = value;
[self.view setNeedsDisplay:YES];
}
- (void)drawRect:(NSRect)frame {
[self.view drawRect:frame];
if (isHighlighted) {
[NSBezierPath setDefaultLineWidth:6.0];
[[NSColor keyboardFocusIndicatorColor] set];
[NSBezierPath strokeRect:frame];
}
}
I didn't seem to fix it, and because no one gave me any answers, I fixed it by making an NSView subclass and adding it to my viewcontroller like this.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
draggable = [[DragView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
[[self view] addSubview:draggable];
}
return self;
}
I've never done OS X programming, but the problem is that since you're registering self.view to receive drag and drop, your self.view should handle the drag and drop operations and not your view controller. So you're correct in subclassing NSView to DragView, and you should pass the drag operations back to the view controller.
Also, I believe - (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender should be implemented.

Resources