Cursor above siblings - cocoa

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

Related

Cursor blinking when NSTextView is not the first responder?

I have an NSTextView object within a complex custom view. I need that custom view to be the first responder (for multiple reasons, e.g. to have its focus ring drawn properly). But the NSTextView cursor must still blink as if the text view was the first responder.
Here's essentially what I want to see in my application (a screenshot of the search field in Apple Mail):
Note that the text view is the empty area with the cursor located at the beginning of it. The other elements belong to the parent custom view, which has the focus ring around it. The cursor is blinking!
I couldn't implement that behavior using the standard controls. My final solution is to put the search field in another custom view with broad margins and implement a custom focus ring drawing.
Here's how my drafty control looks like:

How to call NSScrollView autoscroll-method programmatically

I have simple chat application with text messages view-based NSTableView as you can see at the picture below.
Each message contains NSTextView instance having height to fit all the text.
All I need is to start NSScrollView (which NSTableView-instance is enclosed by) autoscrolling while the user selecting text dragging mouse far enough. Unfortunately, autoscrolling doesn't appear. In case of dragging somewhere outside of the text views all succeed.
I tried to call autoscroll:-method directly by simply push NSEvent-instance from NSTextView-subclass "mouse dragged"-event (like in example from this article):
- (void)mouseDragged:(NSEvent *)event
{
[self.scrollView autoscroll:event];
}
As I've overrode all the mouse events and implemented all the text selecting, this method often invokes. But the autoscrolling doesn't seem to work.
UPDATE
I figured out that before calling -autoscroll:-method there must be -mouseDown: of the same object. But it breaks my text selecting mechanism. The point even not in being first responder, there must be nothing but the mouseDown:-method.
Normally, a text view is within a scroll view of its own. Even if that's big enough to show all of the text without scrolling, it's still there. A call of -autoscroll: on anything within that scroll view (possibly including that scroll view itself?) will just try to scroll that scroll view, not the scroll view that contains the table view.
Try calling -autoscroll: on a view higher up in the hierarchy. Either self.scrollView.superview, the table cell view, or the table view.
Note, though, that the table view's scroll view will keep scrolling even after the cell view containing the text view is fully on-screen. In fact, it may keep scrolling it so far that it's off the screen in the other direction. Basically, it doesn't know that you're trying to select within the text view so it doesn't know to stop when the selection extends all the way to the edge of the text view.
Another approach might be to try to use a "bare" text view with no enclosing scroll view. I don't think IB will let you do that, so you'd have to do it programmatically. Bare text views don't play well with auto layout, though.

NSSavePanel, setAccessoryView and animation

I'm making a Cocoa application which has an NSSavePanel. During the lifetime of the modality of this panel, I allow the user to toggle between two different accessory views (call them View A and View B) for this panel via a checkbox in both of these views. I'm building on Snow Leopard.
View B is larger heightwise than View A. When switching from View B to View A, Cocoa starts with the height of the save panel plus View B's height, draws View A at the bottom of the panel with a blank space at the top of View A and then slowly animates this space away so that View A slides upwards. This looks okay.
When switching from View A to View B, Cocoa draws View B's components at the very top of the save panel so that they overlap the save panel's own components (text fields, buttons, etc.). It then slides View B downwards to underneath the save panel's own components. This looks ugly.
First off, I'm not sure how to reason about the proper way to animate the transition from View A to View B. Secondly, I'm not sure to accomplish it. I suppose I could just have one accessory view and just show and hide components in this when switching from basic to advanced mode, but this seems kind of a kludge.
Any suggestions? Thanks in advance.
The easiest way I've found to do things like this is to use an NSTabView with no visible tabs that does NOT draw the background. A and B are subviews of the tab view. Use the checkbox to toggle between the subviews of the NSTabView -- create an action method that uses -[NSTabView selectTabViewItemAtIndex:]. Then you don't have to worry about the height changing and Cocoa handles the transition.

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.

Sizing a control to fit its container in Interface Builder

Let's say I have a split view, and I want to fill half of it with a table view (a fairly common use case, I would think). Is there any way to tell the table view to size itself to fit the split view or do I really have to size it manually?
I've done this, the way Jon Hess mentions first. Assuming you're using Interface Builder version 3:
Drag and resize your GUI (tableview from what I understand?) component to fit into the enclosing area the way you want it.
Click it to select it.
Press Command-Shift-I to open the inspector window for this GUI component. The inspector window should now actually show that you've selected a "Scroll View".
Click the "ruler" heading to be able to set the sizing. You'll see to the right an animated representation of how your GUI component will behave within its enclosing GUI component, and to the left another represenation of the same, without animation, but with four springs and two struts that you can turn on or off.
Turn all six things on, making them red.
VoilĂ  :-)
It's generally easier to create the subviews first, then use the Layout/Embed Objects In/Split View menu item to create the split view around them.
As far as I know, doing it manually is the only way to go. However, if you turn on "snap to cocoa guidelines", the inner view will snap to the edges of the enclosing view as you drag towards them. This makes it easier than having to manually mouse the edges into place, or manually edit the sizes to match.
You can set all of the springs and struts of the table view to "on" in the size inspector and that will cause the table view to fill the split view. Alternatively, you can use the outline view in the main document window to place the tableview's enclosing scroll view directly into the splitview instead of in an intermediary custom view.

Resources