mikeash / NSRectangle

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

This is a 3rd party implementation of the NSRectangle class and related classes discussed here:

http://openradar.appspot.com/radar?id=1567402

The text of the bug follows for those who want to read directly and not click.

NSRect/CGRect (and similar structs like NSPoint and NSSize) are error-prone and can be tough to use due to the multitude of coordinate spaces we deal with. Many new Cocoa programmers don't understand the difference between bounds/frame and tend to resort to trial and error to pick the right one. In cases where frame and bounds happen to be numerically similar, an error can persist in code for a long time.

My understanding is that NSRect and friends are structs mainly for efficiency reasons which were a big deal back when this stuff could be expected to run on a 25MHz 68040. This is probably less important today.

I propose a new class, let's call it NSRectangle, which would encompass the functionality of NSRect but would hold not only its origin and size but also its coordinate system. An NSRectangle object could be passed around from one view to another or from one window to another without needing to do any manual conversions, as the object would hold enough information to do them on its own. Something painful and error prone like lining up a window with an NSView's on-screen location would become a simple matter of initializing the window with [view frameRectangle] (assuming -frameRectangle is an equivalent to -frame which returns an NSRectangle object).

There are obviously a lot of compatibility concerns which would require keeping the old structs around pretty much indefinitely. However, I think these new classes could still bring a lot of benefit and supersede the structs in a lot of cases.

Here are some code examples of how this class might work and be used:

// position a subview in the bottom middle of this view
NSRectangle *frame = [self frameRectangle];
[frame setHeight: [frame height] / 2];
[frame setOriginX: [frame width] * 3 / 4];
[frame setWidth: [frame width] / 2];
[subview setFrameRectangle: frame];

// position a window directly over this view
NSRectangle *frame = [self frameRectangle];
NSWindow *window = [[NSWindow alloc] initWithFrameRectangle: frame ...];
[window orderFront: nil];

// position a window next to this view on the right
NSRectangle *frame = [self frameRectangle];
[frame setOriginX: [frame maxX]];
[frame setWidth: 42]; // 42 pixels in VIEW COORDINATES, may be different in screen coordinates, but we may want to size the window relative to view coordinates anyway
NSWindow *window = [[NSWindow alloc] initWithFrameRectangle: frame ...];
[window orderFront: nil];

// position a window next to this view on the right, sized in screen coords
NSRectangle *frame = [self frameRectangle];
[frame setOriginX: [frame maxX]];
[frame setWidth: 42 inCoordinateSystem: [NSScreen coordinateSystem]];
NSWindow *window = [[NSWindow alloc] initWithFrameRectangle: frame ...];
[window orderFront: nil];

// create a 200x200 window with origin at 100,100 on the screen
NSRectangle *rect = [NSRectangle rectangleWithRect: NSMakeRect(100, 100, 200, 200) inCoordinateSystem: [NSScreen coordinateSystem]];
NSWindow *window = [[NSWindow alloc] initWithFrameRectangle: rect ...];

// create a 200x200 window with origin at 100,100 relative to a view
NSRectangle *rect = [NSRectangle rectangleWithRect: NSMakeRect(100, 100, 200, 200) inCoordinateSystem: [view coordinateSystem]];
NSWindow *window = [[NSWindow alloc] initWithFrameRectangle: rect ...];

// handling events
// NSPointObj is a hypothetical class version of the NSPoint struct

// see if a mouse event is within this view
NSPointObj *loc = [theEvent location];
if([[self frameRectangle] containsPoint: loc])
    ...

// see if a mouse event is within various views
NSPointObj *loc = [theEvent location];
if(([[view1 frameRectangle] containsPoint: loc])
    ...
else if(([[view2 frameRectangle] containsPoint: loc])
    ...
else if(([[view3 frameRectangle] containsPoint: loc])
    ...
// NOTE: view1, view2, and view3 don't need to be siblings for this to work
// in fact, they don't even need to be in the same window!

About


Languages

Language:Objective-C 100.0%