Appkit: tracking rectangles outside visible rect interfere with other views - appkit

Some NSView subclasses have tracking rectangles that update the cursor. This is the case for NSTableHeaderView, which sets the resizing cursor when the mouse hovers a column separator.
These tracking rectangles show outside the visible rectangle of the view. Typically, an NSTableHeaderView is inside an NSScrollView. If the clipped part of the table header is behind another view next to it, tracking rectangles cause cursor updates when the mouse is inside this other view. This would disturb the user.
I suppose this is expected behaviour, but I'm surprised that NSTableHeaderView (as well as NSTableView) doesn't discard tracking rectangles that aren't in the visibleRect
What's the best solution to remove these unwanted tracking rectangles? I'm thinking about overriding -updateTrackingAreas and removing any tracking area that isn't in the visible rect, after calling super. I'm assuming the problematic NSView subclasses uses this method to update tracking rectangles.

Related

Cursor above siblings

Suppose there is a window with a very simple UI hierarchy which has just two siblings: NSTextView and NSButton, and they do overlap.
My question is, why is the cursor different when hovering over the button, depending on whether there is the textview below it or not? Why is the text cursor "leaking" through the button? How do I make the button retain its cursor regardless what is beneath it?
I thought I could create an NSView, place the button inside it and somehow make the view "opaque" but I didn't get too far...
What I'm trying to do is to have a button which "floats" above the textview and still displays the proper (normal) cursor.
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CocoaViewsGuide/WorkingWithAViewHierarchy/WorkingWithAViewHierarchy.html
For performance reasons, Cocoa does not enforce clipping among sibling
views or guarantee correct invalidation and drawing behavior when
sibling views overlap. If you want a view to be drawn in front of
another view, you should make the front view a subview (or descendant)
of the rear view.
You can use NSTrackingArea to update cursor manually:
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/EventOverview/TrackingAreaObjects/TrackingAreaObjects.html

Auto layout NSWindow respects minimum size in IB simulator, but not when running for real

I have a window I'm setting up with auto layout. There is a view in the middle of the window that contains three controls, and I would like the window to refuse to resize horizontally smaller than the intrinsic size of those three controls.
The outer buttons both have horizontal space constraints to "stick" them to the outside of their superview, and the checkbox in the middle has a horizontal space constraint sticking it to the left side of the "Sync text" button. There is also a >= constraint between the "Sync outline" button and the checkbox, to make sure they don't overlap, but the checkbox prefers to hang to the right. All these constraints have a priority of 1000. The window itself has no minimum size specified.
When I use the "Simulate Document" command in Xcode, everything works as I'd expect, and the window won't let you size it smaller than in the screenshot above. However, when I run my application, the window does allow resizing smaller than that width, so that the buttons start to shrink and eventually the controls overlap each other. I'm not implementing any of the size related window delegate methods, so I don't see any place in the app's code where it might be influencing the resizing.
Any ideas on what could be causing this difference in behavior?
OK, I finally figured out what the heck was going on here. It turns out the problem was that I was implementing the -splitView:constraintMinCoordinate:ofSubviewAt: delegate method (as well as the maxCoordinate one) to restrict the size of the split subviews in the vertical direction. Yes, restricting the vertical resizing of the split view affected the horizontal layout of the buttons.
It appears that what happens is that, if you implement those delegate methods, NSSplitView reverts back to using autoresizing masks to layout the subviews rather than auto layout constraints. Since the view containing those buttons is no longer participating in auto layout, the buttons smush together when you resize the window small. In the simulator, the split view doesn't have a delegate set, so all the auto layout stuff works fine in that environment. Note that merely having the methods implemented is enough to trigger this, even if they just return the proposed coordinates unchanged.
The solution ended up being quite easy, which was to delete the delegate methods and replace it with a vertical constraint on the subview to restrict its size instead.

Drawing an NSTableView's background outside of its bounds

I'm having a problem since Lion introduced elastic scrolling (pictured below). When you scroll my table view (cell-based, with alternating row colors) beyond its bounds, the background doesn't draw. I've tried doing my own drawing in -[drawBackgroundInClipRect:], but it seems like you can't exceed the bounds of the table view. How can I extend the background into elastic scrolling territory?
In Answer to Your Question
A view drawing outside its bounds is generally a no-no. When using alternating background colors, the NSTableView draws its background directly. But in a view-based table view, NSTableRowView is used and if it has its own background color, this is poses even more challenge.
The Bad News
The assemblage of NSScrollView (and its various parts), NSTableView, and NSTableHeaderView is complicated on its own. Once you throw view-based functionality into the mix (where each row has a view and each cell has their own view, and each are reused, animated around, etc.), overriding this behavior "is no way to go through life, son!" ;-)
The Good News
The issue of alternating background colors not extending in an elastically-stretched scrolled table view has been resolved (at least on 10.10, that I can tell), so this is no longer an issue unless you have row/cell views with custom backgrounds or just background colors.
A General Solution For Custom Document (Scrolled) Views
For all other scrolled views with ruled backgrounds you wish to extend for elastic scrolling, you'll need a custom NSScrollView subclass that expects a document view (your custom scrolled view) to conform to a protocol you define (like -(NSImage *)backgroundImageForClipViewBounds:). The scroll view would observe its content view (NSClipView) for bounds change notifications and flag itself for display. When the scroll view's -drawRect: is called, it would then ask the scrolled view for its -backgroundImageForClipViewBounds: (via your protocol) and draw it into itself, thereby making the scrolled view's "infinite background" its own.
I haven't tested this theory but I believe it would work. I hope this helps.

NSOutlineView badges in NSSplitView

I have an NSOutlineView which I draw badge numbers to the right side of cells using drawAtPoint:, NSAttributedString, and of course NSBezierPath. My problem exists when resizing of the outline view occurs when within a subview of an NSSplitView. The badges move along with the resize to the left or right. When they get to the text of the cells themselves they do not stop or truncate the text under them. It just flies right over.
Is there a way to have the cell recognize the custom drawn view next to it and truncate text accordingly? I have tried the solution PXSourceList already, but that did not help either.
"PXSourceList solution" working good. You subclass NSOutlineView and overload frameOfCellAtColumn for this particular task. At this function you need to decrease width of cellFrame, returned from super call, by the width of your badge plus padding.

make NSRect selectable

Is there a simple way to create a selectable NSRect in Cocoa? In need a rectangle that can be selected and stays selected after a mouse click.
Thanks.
NSRect is just a struct with a position and size. It's not an object that can actually do anything or have any properties other than a width and height. It sounds like what you want is to create an NSView that can be selected. (Here's Apple's Guide on the subject.)
Though not as immediate as you would like, you may be interested in the management of tracking rectangles and tracking areas performed by NSView class.
This mechanism allows you to define specific areas of your custom view. Then, an event is generated whenever the cursor enters or leaves the area, or a mouse button is pressed in this area (-mouseEntered:, -mouseExited:, -mouseDown:, -mouseUp:, -mouseDragged:, ... of NSResponder class). This up to you to define what you want your application do in response to these events (set the rectangle as selected and display it accordingly).
For an example implementation of this, take a look at the Sketch example included with the Apple developer tools (look in /Developer/Examples/AppKit). Sketch allows the user to create new graphics (including rectangles, but also ovals, lines, and text), select them, move them around in the document, etc. In particular, you'll probably want to look at the SKTGraphic class, which represents a single graphic object in the document, and the SKTGraphicView class, which is an NSView subclass that perform the actual layout and drawing, handling mouse events for dragging views around, etc.

Resources