Pinning a NSTableColumn so that it does not scroll horizontally? - cocoa

I'm trying to figure out a way to have a NSTableColumn be pinned to the left side of my NSTableView. What I have been thinking of is putting two NSTableView's side by side, where the first one contains the 'pinned' column and the second on contains the dynamic data. Setting the first table to disable horizontal scrolling, then detecting when either table is scrolled vertically and keeping the two in sync.
What I'm wondering, is if anyone else has any experience in doing something similar? I don't want to re-invent the wheel if its already been done.

Thats exactly what I did. Two NSTableView's directly beside each other. The first I subclassed the NSScrollView and modified the scroll events to do nothing. The second I subclassed again the NSScrollView and modified the scroll events to cause the header to mirror it. Works great.

Related

Make sure NSTrackingArea refreshed in Nested NSScrollViews

I have an NSCollectionView in an NSScrollView.
The scroll view scrolls horizontally to move along the line of items.
Inside each each collection item is a vertically scrolling NSOutlineView.
I have NSButton objects for opening and closing collection items - as supplementary views in my collection.
I set up NSTrackingAreas on these buttons to support mouse over effects.
This works correctly, until I scroll, at which point the NSTrackingArea areas are clearly left behind (the mouse over effects happen when the mouse is where the button was, not where it is).
I rebuild my tracking areas in updateTrackingAreas in my button class, and this is called, but not often enough.
I have tried using .inVisibleRect when setting up my tracking areas, rather than explicitly rebuilding them, but that doesn't improve the tracking update.
I have tried calling updateTrackingAreas on the NSCollectionView when scroll occurs, but it is never passed down to the child views as I expected it would.
As a side note, I also have NSTextViews in my collection view items with toolTips that are very flakey too. They are often left hanging. Pointing hand cursors over links are often misaligned.
It feels as though the default updateTrackingArea is over-optimised and is not being called as often as it should.
So, I am about to embark on building my own tracking-area-tracker to register and update my views when they are not updated by default...
...but maybe someone can see something obvious that I am missing? Thank you.
The tracking area setup can be subtly broken when nesting scroll views incorrectly. See the answers regarding nesting scroll views here for details:
NSScrollView inside another NSScrollView

NSScrollView with sticky top, left and bottom 'headers'

I'm trying to create a timeline control in Cocoa. This is what I am trying to achieve. It's basically a standard timeline design.
However, I don't know which approach to take. The problem lies with the top ruler, the left track list and the bottom audio waveform display. These three parts need to always be visible and 'stick' to the edges. The ruler and audio waveform should only scroll horizontally, while the track list on the left should only scroll vertically.
For the top ruler, NSRulerView seems appropriate since it's just a ruler.
For the left view and the bottom view I don't know which route to take. I've played with using a wide vertical NSRulerView for the track list. This works but creates additional problems. For example: the top ruler appears above the track list.
I've composed four options so far:
Forget NSRulerView and draw everything custom in the document view. This seems feasible but sidesteps built in NSRulerView functions. Also, I need to find a way to shorten the scrollbars so they don't overlap the side and top views.
Use NSRulerViews for the top and left side. The bottom side will then probably be drawn manually in the document view.
Place the left view outside the scrollview and manually scroll it up and down by linking it to the main scroll view. Use NSRulerView for the top, manually draw audio waveform in document view.
An NSScrollView embedded in another NSScrollView. The outer handles horizontal scrolling, the inner scroll view handles vertical scrolling. Possible I think, but it seems hacky.
So my question boils down to: Which route to take?. Can anyone shed some light on this issue and point me in the right direction?
What I understand:
You want a view to the left of an NSScrollView which scrolls vertically with the NSScrollView while ignoring horizontal scrolling.
You want a view below an NSScrollView which scrolls horizontally with the NSScrollView while ignoring vertical scrolling.
You want rulers.
To achieve this task:
Use 3 separate scroll views which do not overlap and donot inherit one another.
Activate rulers in whichever view(s) you would like them to appear.
Synchronize the scroll views (so that when one scrolls, the other scrolls accordingly).
How to synchronize scroll views is in the help. See User Experience > Controls > Scroll View Programming Guide for Mac > Synchronizing Scroll Views. This is also indirectly linked in the header of the help guide for NSScrollView.
If you want the three scroll views to be contained within an NSSplitView for resizing simplicity, then a fourth view must be added to consume the unused corner (good place to put controls). Since an NSSplitView can only be split vertically or horizontally, you will have to create an NSSplitView containing 2 split views with each of those split views containing 2 views that you actually see (splitting in one direction and then the other). The resizing of the split views will have to be synchronized in a manner much like the scrolling is synchronized to retain a straight cross of all four views.

How to "stick" a UIScrollView subview to top/bottom when scrolling?

You see this in iPhone apps like Gilt. The user scrolls a view, and a subview apparently "sticks" to one edges as the rest of the scrollView slides underneath. That is, there is a text box (or whatever) in the scrollView, that as the scrollView hits the top of the view, then "sticks" there as the rest of the view continues to slide.
So, there are several issues. First, one can determine via "scrollViewDidScroll:" (during normal scrolling) when the view of interest is passing (or re-appearing). There is a fair amount of granularity here - the differences between delegate calls can be a hundred of points or more. That said, when you see the view approach the top of the scrollView, you turn on a second copy of the view statically displayed under the scrollView top. I have not coded this, but it seems like it will lack a real "stick" look - the view will first disappear then reappear.
Second, if one does a setContentOffset:animated, one does not get the delegate messages (Gilt does not do this). So, how do you get the callbacks in this case? Do you use KVO on "scroll.layer.presentationLayer.bounds" ?
Well, I found one way to do this. When the user scrolls by flicking and dragging, the UIScrollView gives its delegate a "scrollViewDidScroll:" message. You can look then to see if the scroller has moved the content to where you need to take some action.
When "sticking" the view, remove it from the scrollView, and then add it to the scrollView's superview (with an origin of 0,0). When unsticking, do the converse.
If you use the UIScrollView setContentOffset:animated:, it gets trickier. What I did was to subclass UIScrollView, use a flag to specify it was setContentOffset moving the offset, then start a fast running timer to monitor contentOffset.
I put the method that handles the math and sticking/unsticking the child view into this subclass. It looks pretty good.
Gilt uses a table view to accomplish this. Specifically, in the table view's delegate, these two methods:
– tableView:viewForHeaderInSection:
and – tableView:heightForHeaderInSection:

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.

Setting one side of an NSSplitView programmatically

I've got an NSSplitView and on the left side I've got a tableView (like a source list) and depending on row selection, I want to change the the right side of the split view. I can't quite figure out how to do this.
When I add my desired subview to the splitview, it adds another split (so now there's 3 views total... not what I wanted).
[mySplitView addSubview:myCustomView];
How do I properly set the right side of my splitView?
Update
Using
[mySplitView replaceSubview:[[mySplitView subviews] objectAtIndex:1] withSubview:myCustomView]
Seems to work, however it's resizing the split view rather oddly, how can I stop this? In IB there's an option to turn off autoResizesSubviews but I can't uncheck this. Any ideas?
Try setting the frame of your new view to that of the old view before performing the swap.
Also, you might take a look at BWToolkit which provides a much nicer way to set the sizes for the sides of a split pane.

Resources