Jumping warped cursor - objective-c

I'm trying to move the location of a Mac cursor using Objective-C along a path outside of any UI element (not just on some window, but around the entire screen irrelevant of what the mouse is hovering over). I don't want to directly warp the mouse to a position, but rather progressively move it there (i.e. iterate through a loop, and in each iteration move the cursor 1 pixel to the right).
The problem is that the cursor constantly jumps back and forth over the horizontal center line of the screen (if I start the cursor at y=289, it jumps to y=511, and then back to y=289, and so forth, as my screen is 800 pixels high) even if I don't actually move it anywhere.
NSPoint mPoint = [NSEvent mouseLocation];
NSPoint mouseWarpLocation = NSMakePoint(mPoint.x, mPoint.y);
CGWarpMouseCursorPosition(mouseWarpLocation);
The code above effectively warps the mouse to its current position, but for some reason the cursor jumps back and forth over the horizontal center line. Any thoughts as to why or what I can do to fix it?

The problem is that AppKit (which provides the NSEvent class) and Quartz Display Services (which provides CGWarpMouseCursorPosition) use different coordinate systems for the screen.
In Quartz, the origin of the screen coordinate system is at the top-left corner of the “main” screen, which is the screen that contains the menu bar, and Y coordinates increase as you move down the screen.
In AppKit, the origin of the screen coordinate system is at the bottom-left corner of the main screen, and Y coordinates increase as you move up the screen.
So if you ask AppKit for the mouse location (in screen coordinates), you need to convert the Y coordinate to the Quartz coordinate system before passing it to a Quartz function.
To transform the Y coordinate, subtract it from the height of the main screen:
NSPoint point = [NSEvent mouseLocation];
point.y = [NSScreen mainScreen].frame.size.height - point.y;
CGWarpMouseCursorPosition(point);

Related

How to calculate the correct location of a vertical NSRulerMarker?

What is the correct formula for the location of an NSRulerMarker on a vertical NSRulerView, if the client view is flipped?
The situation: I have a view (let's call it the "main view") that is embedded in an NSScrollView with rulers, and it has subviews. The user can drag these subviews around, and while dragging, I want to indicate the current position on the rulers.
The main view is flipped: The zero point is top-left.
The horizontal position is pretty simple:
NSPoint scroll = myScrollView.documentVisibleRect.origin;
NSRect rect = mySubView.frame;
rulerMarkerDragLeft.markerLocation = rect.origin.x - scroll.x;
However the same method for the vertical position...
rulerMarkerDragTop.markerLocation = rect.origin.y - scroll.y;
does not work. The marker is only in the correct position when the scrollview has been scrolled down to the extreme bottom. For every n points scrolled back up, the marker location is n points too high. This is independent of the main view's size or the size of the visible area.
I can't seem to wrap my head around this problem; I guess there is a value I need to subtract from my result that expresses how far up the scrollview has been scrolled (or rather, how much further it can be scrolled down), but I don't think I can derive that value from myScrollView.documentVisibleRect...?
I may have overlooked something simple, but I can't find the solution.
Edit 2022-11-02 17:17 CET: Found the problem. I had set the NSRulerViews clientView to the contentView of the window. I am now setting it to the "main view" (ie. the view inside the scroll view), and now it works "automagically": I just set the marker locations to the subviews frame, no correction for scroll position or anything else needed.
The solution was simple: the ruler views' clientView needs to be set to the view that is inside the scroll view, not the main content view of the window.
The positioning of the ruler markers is now very straightforward: you just use the local coordinates inside the view, ie. the subviews' frame values.
No correction for scroll position, view height or such necessary.
My mistake was assigning the window's main content view as the rulers' clientView.

Camera for Spotlight

I have two orthographic cameras. The first one is for the main display and the other one is used for a spotlight effect.
What I want is, if I move the second camera (spotlight), I want the view port rect to be normalized as well. Right now, if I move the second camera's Transform, it looks at the camera's direction but the display is not moving.
So, if the display is at the bottom-right corner, and I move the camera at the top-left corner, I want to display the camera at the top-left corner as well instead of displaying it at the bottom-right corner.
Also, I'm building it on iPad.

Getting co-ordinates of bitmap on mouseDown in NSImageView

I am working on an app where I display unsupported (by XCode) file format). So I've subclassed NSBitmapImageRep to display it in a subclass of NSImaageView. I've set it up to be proportionally scallable (up or down). Now I need to add a possibility to get coordinates of pixel in a bitmap. So I've ovveride mouseDown: method:
- (void)mouseDown:(NSEvent *)theEvent
{
NSLog(#"mouseDown: %ld", [theEvent clickCount]);
NSPoint point = [theEvent locationInWindow];
NSLog(#"point x: %f and y: %f", point.x, point.y);
}
After getting NSPoint I should try to convert it to co-ordinates of a bitmap BUT first I have no idea How to solve the problem that locationInWindow returns NSPoint of a NSImageView, not of the bitmap which is ussually smaller and has unused margins in NSImageView, but I can click on the margin and mouseDown event returns me NSPoint in that margin. Do you have any idea what I shoud do?
You need a view to image matrix. It's a matrix that maps view coordinates to image coordinates. Usually it will be a combination of scale and translation.
First you need to decide if you want to scale the image so that it is entirely visible, but fits within the window, or so that it entirely fills the window. (Or there are other options, like always showing the image at 1:1 regardless of the size of the window.) That will determine the scale of the image.
Next you need to decide how to position the scaled image. If you scale it to always fit in the window, and there's padding, do you favor the left and top of the window, or always try to center it? IF it's scaled to always fill the window, is it centered vertically or horizontally in the window? Or is the origin of the image always displayed in the lower left of the window?
Once you've figured out the scale and translate, you can compose a single matrix from the 2 of them. Once you've done that, get the inverse of the matrix, and that will transform your view coordinates into image pixels.

Xna scroll-able view

How do I make a scroll-able map. For example, my preferred back buffer is 800x600 and the map is 2400x1800 (approximately 3x3). Also, how do I handle the keyboard state to scroll and do walking. I know most games keep the player centered and scroll the world. The problem with this approach is the corners. There would be a large unmoveable area.
To make scrollable map you can use simple Rectangle or ViewPort (named camera):
' Initialize camera with size of game viewport
Dim viewport As Viewport = spriteBatch.GraphicsDevice.Viewport
Dim camera As New Rectangle(viewport.X, viewport.Y, viewport.Width, viewport.Height)
' Draw method code
spriteBatch.Begin()
spriteBatch.Draw(image,
New Rectangle(0, 0, viewport.Width, viewport.Height), // Destination rectangle
camera, // Source rectangle
Color.White)
spriteBatch.End()
By changing camera.X and camera.Y values you can adjust origin from where your image is drawn thus moving camera around. For example following code would move your camera to the right:
Dim keyboardState As KeyboardState = Keyboard.GetState()
If keyboardState.IsKeyDown(Keys.Right) Then
camera.X += 1
End If
Walking can be done very similarly, by increasing character position X and Y coordinates when according buttons are pressed.
Keeping player in the center of the screen is a bit trickier. Basically you want to keep character in the center of the screen at all times except when distance between it and edge of world is less then half the screen. In this case stop moving camera and start moving character off of center to the desired side.

Difficulty finding correct anchor point for rotation transforms

I'm animating a button's position, rotating it around a circle. This creates a UISwitch-like behavior, except it is a lot more fancy. The button rotates, but it ends up off the desired position by about 0.25 radians. I'm trying to figure out where to put the anchor point to make the button rotate in a perfect circle around its origin.
Here's the code that I use to make the button "orbit" with a 120 pixel radius from the original location.
float offsetX=120;
float offsetY=0;
enableDisableButton.layer.anchorPoint =
CGPointMake(offsetX/enableDisableButton.frame.size.width,
offsetY/enableDisableButton.frame.size.height);
I use the following method to do the calculations. Passing an argument of 90 for degrees, I expect to see the button start at a 180˚ position and move to 90˚, still 120 pixels away from its origin
-(CGAffineTransform)calculateLabelPositionFromFixedPointWithOffsetClockwiseInDegrees:(float)degrees
{
float rotation = degrees*(2*M_PI/360);
CGAffineTransform transform24 = CGAffineTransformMakeRotation(rotation);
NSLog(#"rotation: %f", rotation);
return transform24;
}
This little 0.25 radian or so offset means that I need to visually confirm the location of each button and cannot easily adjust its location programmatically. Any help in determining the correct way to rotate the button is appreciated.
I tried other ways to rotate objects. For example, I have an arrow
<--------x, and I would like to rotate this arrow in a circle around x . What is the correct anchor point placement for this operation? Is it [1, 0.5]?
An easier way to do this kind of rotations is to put an object within a symmetric UIView, center it at the desired point of rotation and assign a rotation transform. This works, but requires the view to be twice as big:
Y----x----Y < this rotates Y around center point X without any anchor point adjustments. this is a very useful method to rotate arrows within analog gauges and such.
"An easier way to do this kind of rotations is to put an object within a symmetric UIView, center it at the desired point of rotation and assign a rotation transform." this way is fine.
The anchor point of your enableDisableButton in the example would be
CGPointMake(offsetX/enableDisableButton.frame.size.width, 0)
i.e. not vertically centered in your button. Rotating around the anchor point would result in the button being offset to the top or bottom of the desired position. The transform looks alright, so I think it is just the anchor point. It should be:
CGPointMake(offsetX/enableDisableButton.frame.size.width, 0.5f)