I am making an app for school and I would love to change the cursor picture when the mouse is clicked in a certain NSView area.
I know that you can use mousedown, mouseup and other events, but I don't really know how to put them in my code in order for the cursor picture change to work.
Have the custom NSView and override resetCursorRect,
Refer the example code below
-(void)resetCursorRects{
//[self log:#"Inside Reset Cursor Rect"];
NSRect viewRect = [self frame];// change it accordingly
[self addCursorRect:viewRect cursor:[NSCursor pointingHandCursor]];
viewRect = [self.pMailImageView frame];
[self addCursorRect:viewRect cursor:[NSCursor pointingHandCursor]];
viewRect = [self.pDialImageView frame];
[self addCursorRect:viewRect cursor:[NSCursor pointingHandCursor]];
}
Related
I have a custom subclass of NSView in my app.
I would like to know the exact point in the view, relative to it's origin, that was clicked with the mouse. (i.e. Not relative to the Window origin, but relative to the custom-view origin).
I have always used this, which has worked perfectly:
-(void)mouseDown:(NSEvent *)theEvent
{
NSPoint screenPoint = [NSEvent mouseLocation];
NSPoint windowPoint = [[self window] convertScreenToBase:screenPoint];
NSPoint point = [self convertPoint:windowPoint fromView:nil];
_pointInView = point;
[self setNeedsDisplay:YES];
}
But now I get a warning that convertScreenToBase is deprecated and to use convertRectFromScreen instead. However I cannot get the same results from convertRectFromScreen, and anyway, I'm interested in a point, not a rect!
What should I use as the correct replacement for the deprecated code above?
Thanks in advance!
This line from your code:
NSPoint screenPoint = [NSEvent mouseLocation];
gets the location of the mouse cursor out of sync with the event stream. It's not the position of the event you're currently handling, which was a short time in the past; it's the position of the cursor right now, which means you're potentially skipping past some important stuff. You should almost always use the position in sync with the event stream.
To do that, use the theEvent parameter that your method receives. NSEvent has a locationInWindow property, which has already been translated to the coordinates of the window which receives it. That eliminates the need for you to convert it.
NSPoint windowPoint = [theEvent locationInWindow];
Your code to convert the window location to the view's coordinate system is fine.
I found the solution:
NSPoint screenPoint = [NSEvent mouseLocation];
NSRect screenRect = CGRectMake(screenPoint.x, screenPoint.y, 1.0, 1.0);
NSRect baseRect = [self.window convertRectFromScreen:screenRect];
_pointInView = [self convertPoint:baseRect.origin fromView:nil];
I have made a sample project with a window and tested the 'old' and new scenario. The result is the same in both cases.
You have to make one additional step: Create a simple rect with the screenPoint as origin. Then use the origin of the new, returned rect.
Here is the new code:
-(void)mouseDown:(NSEvent *)theEvent
{
NSPoint screenPoint = [NSEvent mouseLocation];
NSRect rect = [[self window] convertRectFromScreen:NSMakeRect(screenPoint.x, screenPoint.y, 0, 0)];
NSPoint windowPoint = rect.origin;
NSPoint point = [self convertPoint:windowPoint fromView:nil];
_pointInView = point;
[self setNeedsDisplay:YES];
}
I hope I was able to help you!
Simply use convert(_:from:) can be inaccurate, this can happen when event's window and view's window are not the same. Please check my answer in another question for a more robust way.
https://stackoverflow.com/a/69784415/3164091
I have an NSTextField in a container:
[textField setFrameOrigin:NSMakePoint(0, -t.frame.size.height)];
content = [[NSView alloc] init];
[content setWantLayer:YES]
content.layer=[CALayer layer];
[content addSubview:textField];
[content scaleUnitSquareToSize:NSMakeSize(1, -1)];
content.frame=textField.frame;
content.layer.backgroundColor=textBGColor.CGColor;
The container itself is located in a view with
[view scaleUnitSquareToSize:NSMakeSize(1, -1)];
This is all for obtaining a top left origin for the TextField and it works great, the only problem consist in the InsertionPoint not drawing (at least not in the visible frame).
I presume the InsertionPoint is either not Scaled or translated with the TextField. Other possibility is that InsertionPoint can't be drawn in a layer backed View.
Is there a way to display the InsertionPoint cursor ?
EDIT
After trying all the possibilities out, it seems the InsertionPoint (and the focusRing) are not drawing because of its frame being positioned out of the superviews bounds and its dirtyDrawRect. Is there a way to remove the clipping of an NSView ? I need to be able to place my TextField on every absolute position possible.
I found a way through: implementing the drawing myself.
1) giving a custom TextView as Editor for the window.
- (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)anObject
{
if (!myCustomFieldEditor) {
myCustomFieldEditor = [[TextView alloc] init];
[myCustomFieldEditor setFieldEditor:YES];
}
return myCustomFieldEditor;
}
2) Overiding the drawInsertionPoint method in the custom TextView class.
-(void)drawInsertionPointInRect:(NSRect)rect color:(NSColor *)color turnedOn:(BOOL)flag{
[color set];
NSRectFill(rect);
[super drawInsertionPointInRect:rect color:color turnedOn:flag];
}
For insertion point just make your textfield to first responder.
[myTextField becomeFirstResponder];
I'd like to add a close button to an NSWindow programmatically. I can get the button to display, but there are no mouse-over or mouse-down effects. My "selector" never seems to get called when i click the button. I'm not really sure whats wrong and why this is so annoying.
Here is what I've been messing with:
closeButton = [NSWindow standardWindowButton:NSWindowCloseButton forStyleMask:self.styleMask];
NSView *themeFrame = [[self contentView] superview];
NSRect c = [themeFrame frame]; // c for "container"
NSRect aV = [closeButton frame]; // aV for "accessory view"
NSRect newFrame = NSMakeRect( c.size.width - aV.size.width - 5, // x position c.size.height - aV.size.height - 5, // y position aV.size.width, // width aV.size.height); // height
[closeButton setFrame:newFrame];
[themeFrame addSubview:closeButton];
[closeButton setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
[closeButton setEnabled:YES];
[closeButton setTarget:self];
[closeButton setAction:NSSelectorFromString(#"testClick:") ];
Where "testClick" is just a memeber function of my class and is defined as such:
- (void)testClick:(id)sender
The problem seems to be the call to:
[themeFrame addSubview:closeButton];
where the themeFrame is: [[self contentView] superview] Just adding the button to [self contentView] works, but I'd like it added to the titlebar.
No Interface Builder please...
Potential issue # 1)
The way you're calling "NSSelectorFromString" seems incorrect to me. I don't think you can pass parameters via this way in Objective C.
Try this:
[closeButton setAction: #selector(closeWindow:)];
and create a new "closeWindow:" action that looks like:
- (void) closeWindow: (id) sender;
which closes the window.
Potential issue # 2)
Instead of:
closeButton = [NSWindow standardWindowButton:NSWindowCloseButton forStyleMask:self.styleMask];
NSView *themeFrame = [[self contentView] superview];
Why not use:
NSWindow * parentWindow = [[self contentView] window];
if(parentWindow)
{
closeButton = [parentWindow standardWindowButton:NSWindowCloseButton forStyleMask:self.styleMask];
}
I want to react on hot key press by displaying NSMenu at mouse cursor position.
My application is UIElement and doesn't have its own window.
I know there is method of NSMenu :
-(void)popUpContextMenu:(NSMenu *)menu
withEvent:(NSEvent *)event
forView:(NSView *)view;
But it seems it doesn't work when there is no view :(.
Should I create a fake transparent view at mouse cursor position, and then display there NSMenu, or there is better way?
May it can be implemented using Carbon?
Use this instead:
[theMenu popUpMenuPositioningItem:nil atLocation:[NSEvent mouseLocation] inView:nil];
Here is solution which uses transparent window:
+ (NSMenu *)defaultMenu {
NSMenu *theMenu = [[[NSMenu alloc] initWithTitle:#"Contextual Menu"] autorelease];
[theMenu insertItemWithTitle:#"Beep" action:#selector(beep:) keyEquivalent:#"" atIndex:0];
[theMenu insertItemWithTitle:#"Honk" action:#selector(honk:) keyEquivalent:#"" atIndex:1];
return theMenu;
}
- (void) hotkeyWithEvent:(NSEvent *)hkEvent
{
NSPoint mouseLocation = [NSEvent mouseLocation];
// 1. Create transparent window programmatically.
NSRect frame = NSMakeRect(mouseLocation.x, mouseLocation.y, 200, 200);
NSWindow* newWindow = [[NSWindow alloc] initWithContentRect:frame
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO];
[newWindow setAlphaValue:0];
[newWindow makeKeyAndOrderFront:NSApp];
NSPoint locationInWindow = [newWindow convertScreenToBase: mouseLocation];
// 2. Construct fake event.
int eventType = NSLeftMouseDown;
NSEvent *fakeMouseEvent = [NSEvent mouseEventWithType:eventType
location:locationInWindow
modifierFlags:0
timestamp:0
windowNumber:[newWindow windowNumber]
context:nil
eventNumber:0
clickCount:0
pressure:0];
// 3. Pop up menu
[NSMenu popUpContextMenu:[[self class]defaultMenu] withEvent:fakeMouseEvent forView:[newWindow contentView]];
}
It works, but i'm still looking for more elegant solution.
I am writing a mac app and have used this code to hide the window handle,
[self.window setStyleMask:NSBorderlessWindowMask];
Well this is great, but i still need a handle to move around the window, so is there a way to move around the window from another object like an NSImage, acting like the window handle?
The code for my image is in the .h,
#interface WOWAppDelegate : NSObject <NSApplicationDelegate> {
NSWindow *window;
IBOutlet NSImageView* winView;
}
and in the .m file,
- (void)awakeFromNib {
NSString *inFilePathwin = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"win.png"];
NSImage *winImage = [[[NSImage alloc] initWithContentsOfFile:inFilePathwin] autorelease];
[winView setImage:winImage];
}
So the image is working and showing so how do i link that function?
Hook the mouseDragged event on a NSView subview.
-(void)mouseDragged:(NSEvent *)theEvent
{
CGFloat deltax = [theEvent deltaX];
CGFloat deltay = [theEvent deltaY];
NSRect frame = [[self window] frame];
frame.origin.x += deltax;
frame.origin.y -= deltay;
[[self window] setFrameOrigin:frame.origin];
}
So
subclass NSView as XView
place your handle image in an instance of this view container.
Place the container where you want in the windows main view.
Use this snippet in XView to drag the window around.
Adjust the behaviour with the mouseDown and MouseUp events.