Scrolling NSTextView in OSX Today Widget with scrollwheel - macos

I have the following view hierarchy in Today Widget app:
NSScrollView
NSClipView
NSTextView
When the text in NSTextView is bigger than it's size, I am able to scroll by highlighting text with a mouse, or by using arrow keys.
But when I try to scroll with mouse wheel or trackpad, it does not work. The question is similar to this one: NSTextView does not scroll when created with NSCollectionView, but the NSTextView is now being placed on top of bigger srollview of side panel (where Today widgets are).
I think, it may be related with responder chain. The scrollview of NSTextView does not even get events, such as:
- (void)scrollWheel:(NSEvent *)theEvent or
-(void)mouseEntered:(NSEvent *)theEvent
How can I solve this problem?

Related

NSPageController, deactivate swipe gesture

I'm currently using a NSPageController to navigate between a Master and a Detail View in my OSX Application. I'm basically using it only to support transition animations, since there is no NavigationController on OSX.
However, the default NSPageController is listening on swipe gestures from my magic mouse and trackpad and changes the displayed view on a horizontal swipe. (like going back / forward in your browser). I would like to deactivate this behavior but overriding and intercepting any gesture method in a NSPageController subclass had no effect so far.
It seems like a NSScrollView / NSTableView does absorb these touches since doing a horizontal swipe gesture above any of my TableViews won't result in a view transition. (It only absorbs them for my magic mouse, doing a swipe gesture on my trackpad still results in switching views)
Target OS: Mac OSX 10.9 +
Thanks for your help!
You can make a subclass of NSPageController and overwrite
- (void)scrollWheel:(NSEvent *)theEvent
This should help.

Setting the scrollable area UISCrollView

I tryed to use answer it this quiestion Limiting the scrollable area in UIScrollView however i didnt succeed in my problem.
I have a UIScrollView that contains 3 UIView one after another. When I press on the UIView I add a UITableView under UIView i pressed. At this moment I need to limit scrolling area, so I could scroll only this TableView and UIView.At another press on UIView I hide the UITableView and I can scroll further in horizontal direction. My question is - how its possible to implement scrolling only in that area I described? Only thing I know is I have to change contentSize of my UISCrollView, but when I do it I get to the beginning of UIScrollView.

How to pass scroll events to parent NSScrollView

I need fixed-size NSTextViews inside a larger scrolling window. IB requires that the textviews be inside their own NSScrollViews, even though their min/max sizes are fixed so that they won’t actually scroll. When trackpad gestures are made within the textview frames (regardless of whether they have focus), they are captured by the textviews’ scrollviews, so nothing happens.
How do I tell the textviews’ scrollviews to pass scroll events up to the window’s main scrollview? (Or perhaps I should be asking how I tell the window’s main scrollview to handle these events itself and not pass them on to its child scrollviews.)
The IB structure is like this:
window
window’s content view
big scrollview for window (desired target for scroll events)
box
swappable content view in separate xib
scrollview for textview
textview
And, yes, the window does scroll correctly when the textviews do not have focus.
You needn't create a outlet "svActive" to track your super scrollview. Just write this sentence in scrollWheel event:
[[self nextResponder] scrollWheel:event];
this will pass the event to next responder in the responder chain.
IB does not require you have a text view inside a NSScrollView; this is just the default, because most of the time you'll want your view to scroll. Select the NSTextView and choose Layout > Unembed Objects. Note that after this point, you can no longer move or resize your view in IB. This seems to be a bug.
Here's an example of how to put two NSTextViews in a single NSScrollView.
Add two text views next to each other; put some text in them so you can see what's happening.
Select the views; choose Layout > Embed Objects In > Scroll View. This puts them in a generic NSView inside a NSScrollView.
Select the text views; choose Layout > Unembed Objects.
Turn off the springs and struts (autosizing) for each text view, so they don't resize when you shrink the scroll view.
Take note of the height of the document view (here it's 175).
Make the scroll view smaller. This also resizes the document view (NSView).
Restore the document view to its original size (I set the height back to 175).
Done! Scrolling works as you'd expect.
This is really embarrassing. After weeks of putting it off, I made a first attempt to get a subclassed NSScrollView to behave passively — and it turned out to be a no brainer.
Here’s the subclass:
h file:
#import <Cocoa/Cocoa.h>
#interface ScrollViewPassive : NSScrollView {
// This property is assigned a ref to windowController’s main scrollview.
NSScrollView *svActive;
}
#property (nonatomic, retain) NSScrollView *svActive;
#end
m file:
#import "ScrollViewPassive.h"
#implementation ScrollViewPassive
#synthesize svActive;
// Pass any gesture scrolling up to the main, active scrollview.
- (void)scrollWheel:(NSEvent *)event {
[svActive scrollWheel:event];
}
#end
There’s no need to make outlets for these passive scrollviews; I give them their refs to the main scrollview right after their xibs are assigned as content to the NSBox:
[self.boxDisplayingTextViews setContentView:self.subviewCtllr1.view];
// A textview's superview's superview is its scrollview:
((ScrollViewPassive *)[[self.subviewCtllr1.textview1 superview] superview]).svActive = self.scrollviewMain;
That’s it. Works like a charm.
I find that IB3 and Xcode4 both fight you if you try to do this directly, but you can do it indirectly. First, drag the textview out of the scrollview and delete the scrollview. You'll wind up with an orphaned textview. I don't know any way to get IB to allow you to put this into your window, but it'll be in your NIB. Now, attach an IBOutlet to it, and at runtime do a addSubview: and adjust its frame to move it into whatever scrollview you wanted it to be in.
In my experience, NIBs are a good thing, but every complex NIB I've ever worked with needed some final rearranging in code.
Based on #phaibin's answer, here's how you'd do it in Swift 4.2.
First, subclass NSScrollView and override scrollWheel:
class ScrollThingy: NSScrollView{
override func scrollWheel(with event: NSEvent) {
self.nextResponder?.scrollWheel(with: event)
}
}
Then place the ScrollThingy class (or whatever you name it) on the NSScrollView that is wrapped around your NSTextView. The parent NSScrollView will get the scroll event thereafter.

NSScrollView as subview of layer-backed view bug?

When I make an NSScrollView a subview of a layer-backed view (for example by choosing an NSTextView or NSTableView from IB), I see strange drawing behavior in the scroll view's document view.
To illustrate, I created a simple project with an NSTextView in a window. The only code I wrote is to turn on layer-backing for the window's content view:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[[self.window contentView] setWantsLayer:YES];
}
This is the result when I type into the textview. The red underlines don't line up properly:
http://mowglii.com/random/screenshot.png
Also, the text and underlines jitter a lot when I resize the textview. I've seen the same jitter on resize when I use a tableview (inside a scrollview) instead of a textview.
Any idea what is going on?
NSScrollView indeed misbehaves badly when embedded in a layer-backed view.
Some serious trickery is needed to animate views containing scroll views. You could try turning on layer-backing only once you need to animate. You then need to force the drawing in order not to end up with an empty layer.
Usually, you will however need to go look much deeper in the back of tricks. Namely: Keep layer-backing switched off. Draw the view into an image, display that image in an overlay view with layer-backing enabled. Animate that view to an image of the final state. Then remove the overlay view to reveal the actual final state below.

Cocoa - Giving focus to a WebView in an NSStatusItem

I've set the view for my NSStatusItem to a WebView, but I'm not able to capture hover events in the WebView because my NSStatusItem doesn't get focus, like a normal WebView would.
How do I programmatically give my NSStatusItem or its associated view focus so that the embedded WebView will capture mouse events like a normal WebView?
In case anyone cares, one way I can think of is to have the view for the NSStatusItem be a custom NSView that overrides the NSResponder methods mouseEntered:, mouseMoved: and mouseExited:. Then, I would add the WebView as a subview of the custom NSView, and each time the mouse moves inside the NSView, send the coordinates of the mouse to the Javascript in the WebView, which can figure out what element is at the position of the mouse cursor.
Basically, it would be reimplementing mouse hover at its core. Hopefully there's an easier way though.

Resources