Flip coordinate system of an NSWindow objective-c / cocoa - objective-c

How can I flip the coordinate system of an NSWindow? I know it has a Content View, but how can I flip the coordinate system of that specific View which is of type NSView?
In a sub-view of my NSWindow's Content View I flip the coordinate system by subclassing NSView, placing that in my window, and in that subclassed NSView I implement method isFlipped to return YES. No idea how I could have NSWindow make it's content view out of "MyFlippedSubclassedNSView"

You can't change the internal co-ordinate system of an NSWindow. The closest you can get is to have a flipped view as the content view.
Chances are you don't actually need a flipped content view or window, though. What are you actually trying to accomplish by flipping the co-ordinate system?
No idea how I could have NSWindow make it's content view out of "MyFlippedSubclassedNSView"
Do that. Make a MyFlippedSubclassedNSView instance, and set it as the content view.
Even easier is to do it in IB: Select the window's content view, hit ⌘6 (Identity), and set the view's class to MyFlippedSubclassedNSView.

Looks like you want -[NSView setBoundsOrigin:].

Related

Identifying correct window frame size for filling background color

I am developing in Cocoa, and I am currently having problems with filling the background of a NSWindowController.
I understand that subclassing is the way forward if you want to customise your cocoa app. So I created a custom NSView named whiteView and added this view as a subview to my windowController's contentView; however, there are some issues with completely filling the background of the window. Can anyone explain how I can have the color cover the complete surface area of the window's frame pls. Thank you
These are the results that I have so far.
1) This is the window when I leave it as it is, notice the white color only having covered half of the window.
2)Here is the same window again when I adjust the window far to the right and bottom. The white screen seems to stretch enough so that it covers the elements.
This is how I create the custom view
- (void)drawRect:(NSRect)dirtyRect
{
[super drawRect:dirtyRect];
[[NSColor whiteColor] set];
NSRectFill([self bounds]);
}
And this how I achieve plaster the view onto my window.
WhiteView *whiteBackgroundView = [[WhiteView alloc] initWithFrame:self.window.frame];
[self.window.contentView addSubview:whiteBackgroundView positioned:NSWindowBelow relativeTo:self.window.contentView];
What do I need to do to correctly allow for my window's background to be fully covered in white?
First, the simple solution is to use -[NSWindow setBackgroundColor:] to just set the window's background color. No need for a view.
If you're still interested in how to fix the view-based approach, probably what's wrong is that you haven't set the autoresizing mask of the view to make it follow the changes in the window size. For example, you could do [whiteBackgroundView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable].
However, you could also set the whiteBackgroundView as the window's contentView rather than as a subview of it. The window's content view is always kept at the size necessary to fill the window's content rect. All of the other views of your window would be subviews of the white background view. In my opinion, this is better than making it a sibling that just happens to be at the back. Using relative ordering among siblings views to achieve a particular rendering order is a hack.
Finally, there's no reason to invoke super's implementation in your -drawRect: if the superclass is NSView itself. NSView doesn't do any drawing in its -drawRect:. Also, your subclass takes over full responsibility for the entire drawn contents of its bounds, so you'd overdraw whatever super had drawn, anyway. (Also, you need only fill dirtyRect rather than [self bounds].)
While you're at it, since your class fills its bounds, you should override -isOpaque to return YES for optimization.
Update: regarding the frame of the view: if it's not going to be the window's content view, then you want to set its frame to be its prospective superview's bounds. So, you should have used self.window.contentView.bounds if you wanted whiteBackgroundView to fill the content view.
More generally, if you want the content rect of a window, you would do [window contentRectForFrameRect:window.frame]. But if a view is going to be a window's content view, there's no need to set its frame to anything in particular. It will be resized automatically.
Update 2:
To transfer the view hierarchy from the original content view to the new content view (when you're making the white background view the content view):
NSArray* subviews = [self.window.contentView.subviews copy];
[subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
[whiteBackgroundView setSubviews:subviews];
[subviews release];
(Written for manual retain-release. If using ARC, just drop the -release invocation.)
Regarding the frame to use, as mentioned in the first update: keep in mind that the view's frame should be expressed in the coordinate system of its superview. So, as I said, self.window.contentView.bounds would work if you're putting the new view into the content view. The window's frame and content rect are in screen coordinates. They would be completely incorrect for positioning a view.

In Cocoa View Hierarchy what determines the subView position?

I am new to cocoa /objective-C coming from Java/C# and C/C++ . Cocoa has been giving me lots of headaches. I have read an apple's article on View hierarchy in cocoa. But still confusions.
I need to know when I add a subView to a view programatically not via interface builder. Where exactly will the view be placed relative to other subviews assuming there are other subviews in the same parent view.
In java there are layout managers, in C# there is also vertical/horizontal panel etc, so we know if I add an item/control it will be going to the right of the existing item or to the bottom of it.
So if I do as shown in the following line what exactly determines where the new subview will be placed ??
[[window contentView] addSubview:newView];
Thanks,
The frame of the view defines the rect that it occupies in its superview's coordinates, so its position will be frame.origin. That can be set either before or after you add the subview.
This is spelled out fairly clearly in the View Programming Guide.
It depends on whether you are using Autolayout or not.
If you are not, then when you create a view you call -[NSView initWithFrame:(NSRect)frame] and that frame will will define where the view appears in the superview's coordinates.
_view = [[NSTextField alloc] initWithFrame:NSMakeRect (50, 50, 100, 50)];
will make an NSTextField size 100x50 and it will be placed 50,50 pixels inside the superview.
If you are using Autolayout, then the position of a view depend entirely on what layout constraints apply to it. With Autolayout any frame that you set will be ignored. While autolayout has a steep learning curve, once you set your constraints, it (in theory) means you can ignore the layout.
The frame rectangle gives the view's size and position in the superview. The frame is at position 0,0 (x,y) with a size of 0,0 (w,h) by default. The position in the subview collection is entirely ignored except in rare cases like NSSplitView.
Cocoa doesn't automatically align any views. There is no initial layout mechanism like in .net or java.
You have to position all your views manually by setting their frames in points.
By default, the origin of a fresh initialized view is at (0,0).
AFAIK, the documentation and header file don't specify exactly the origin (x,y) the added subview will be placed. What I do after add a subview is to calculate a new origin (and if applicable) size before repositioning the subview using CGRectMake().

Positioning subviews for rotation

I'm looking for the best technique for positioning subviews of a UIView in order to take into account rotation. The positioning of the subviews is based on the frame of the UIView.
My basic scenario is a top-level modal UIViewController whose view contains a bunch of subviews. I'm getting the rotation notification fine, but I'm struggling with what the best design pattern should be so that my subviews are positioned corrected both normally and during rotation.
I was using layoutSubviews for positioning. layoutSubviews is called both normally (during view creation) and during rotation. The problem is that when it's called during rotation, the frame width/height has yet to be flipped. So, it seems that I cannot reliably do subview positioning during this function. This seems like a major flaw in design as this is the exact purpose of this method, right?
When I'm doing now, instead, is positioning subviews in my own function, passing a CGRect frame that I flip during rotation and leave alone (self.frame) during normal subview creation. Is this correct? Better solutions?
Thanks.

CGContext is being covered by a UIView

I'm not that great with Core Graphics, but I am drawing text on the screen to my CGContext. I am doing this immediately after I add a standard, opaque UIView to my user interface.
Does anyone know why the text I draw after I add my UIView is still at the "bottom" of the user interface?
Thanks in advance.
iOS, like OS X, uses a compositing window manager. Adding and removing UIViews sets their position in the view hierarchy; when and how they're drawn is managed separately. There is no guaranteed relation between when a view is added and when it'll be drawn, and no reason to guarantee one. The content of a view is cached and composited as required from that copy.
If you want to do custom drawing, create a custom UIView subclass, add it to the hierarchy according to where you want it to appear and do your drawing in drawRect: or one of the other override points if you want to render off thread.

"refresh" view on device rotation

I have my view set up in viewDidLoad. All the different frames and such of the subviews have been defined relative to self.view. Therefore it doesn't matter what size self.view is the subviews will always shrink or expand to fit (as it were).
So when I rotate my device I want the view to rotate (easy enough with shouldAutoRotateToInterfaceOrientation:...) but the subviews stay the same shape.
Calling [self viewDidLoad]; makes all the elements fit, but puts a new layer on top of the previous layout (which is obvious... but i'm just saying to explain what I mean).
Is there any way to refresh the frames of the subviews or something? I don't know what other people do to be honest. Am I going to have to put ALL of my views into the .h file as properties and do everything manually on didRotate...?
You have three options:
If autoresizing masks are good enough to position your views, assign the correct autoresizing mask to each subview when you create them.
If autoresizing masks are not sufficient, override willAnimateRotationToInterfaceOrientation:duration: and reposition your subviews in that method. I would create a custom method that takes the orientation as a parameter and is responsible for laying out all subviews. You can then call this method from willAnimateRotationToInterfaceOrientation:duration: and from viewDidLoad.
You could also create a custom UIView subclass and make your view controller's view an instance of this class. Then override layoutSubviews to position all subviews depending on the view's size. This approach implies that your custom view manages its subviews instead of the view controller.