CALayer, NSTextView and scaling - cocoa

In my app I want to provide text scaling in layer backed NSTextView like Apple's TextEdit. I use analogue of it's ScalingScrollView. Also I need to create some CALayer overlays on self.window.contentView. All is ok until I make [self.window.contentView setWantsLayer:YES].
Before [setWantsLayer:YES]
After [setWantsLayer:YES]
I haven't any ideas how to fix this problem.

I've been searching for the solution to the similar issue, too. Finally, I discovered that layer-backed views must be positioned on integral pixels and must not be positioned on subpixels.
E.g. if you dynamically calculate frame of layer-backed view
NSMakeRect((self.frame.size.width - 350)/2, (self.frame.size.height - 150)/2, 350, 150)
you may encounter non-integral values, so you should do something like
NSMakeRect(floor((self.frame.size.width - 350)/2), floor((self.frame.size.height - 150)/2), 350, 150)

Related

How can I position views over a NSTextView such that they have no fixed position, but a sort of gravity to a point?

So I have an NSTextView with text in it. Some of the parts of the text have a NSTextAttachment.Key so I can find their position in the NSTextContainer. I'm adding notes/annotations to the text right now just by hard coding the frame of the annotation to be under the given part of the text. This fails miserably when two annotations are close to each other(they then overlap), or when an annotation's text position is near an edge of the NSTextView(it then gets clipped and cut off).
What I would really like is to set a rule like, this view(the annotation), likes to be close to this given point, but is flexible. This view does not want to overlap other views or go beyond the bounds of the parent view.
The other rule which may be harder is, this view does not want to cover the NSTextView text. Since that text is not a view itself, one solution may be, since I'll know the font size, and the line height, I could calculate that if say the lines of text are at Y positions 100, 200, 300, etc. Then the annotation could only have Y positions of 75, 125, 175, 225, etc.
Some other notes:
This NSTextView is not editable. It is display only and updates based on changes to another NSTextView, so these positions won't need to be dynamic such that a user is adding text in realtime, rather at fixed intervals the editable textview's content is read, the annotations queried from the backend, and then the text is written into the read-only textview's NSTextStorage, and the annotation NSViews are added to the read-only NSTextView.
MacOS/AppKit only. No UIKit
Here is a diagram of the sort of thing I'm aiming to achieve, and was wondering what is the right tool in the AppKit toolbox to try and achieve this? Can something like AutoLayout work with these types of flexible constraints? Or is my only option to rollout something custom that does all of these calculations, and then gives a fixed NSRect to each annotation's NSView?
You can't do it out of the box but there are couple of things you could look into.
Exclusion paths will help you with not covering the actual text view. Whenever you create the note view, just add an exclusion path which could perhaps cover the whole line (meaning a rect of 0, y, fullContainerWidth, lineHeight).
Using NSPopover instead of normal NSViews. They can pop out of the actual window and won't be clipped outside the screen. There is no way to avoid overlapping with them, though.
There are some popover subclasses (such as SFBPopovers) which allow more flexible positioning.
In either case, you will need to do some maths to avoid overlapping. The best way to do this in your case is probably to enumerate the attributes/text attachments. From there, you can figure out which lines will need to have notes displayed, and calculate in advance how much they will take space, and if you'll have to display them both below and above the line.
Note that you will need to do this as you go along, because the layout and
attribute range rects will change as you add exclusions.
If you decide to go with NSViews, you might want to look into creating a specific container NSView subclass for displaying the notes for a single line. It's much easier to handle positioning the notes in local coordinate space, and to figure out how much space they take. You can then display this specific view on top of your NSTextView where needed.

Hiding Titlebar in NSWindow, rounding the corners and keeping the shadow

I like the way the developers behind Vox.app have created a custom titlebar and still kept the original shadow.
If you set the styleMask = NSBorderlessWindowMask it will create another kind of shadow, and the rounded corners are gone.
And it doesn't seem to be that easy to recreate those shadows especially when you also want rounded corners.
I have taken a window shot of the app that I like. Look at the drop shadows and the title bar.
Is it possible (I assume) to do this? And if so, how?
Is it possible (I assume) to do this?
Yes, this is possible.
And if so, how?
You need to subclass the NSWindow and NSView, set the background color, use custom buttons etc.
For curvy-corners, you need to draw using bezier path. I tried reached somewhat near, however titlebar's color is not changed in this screenshot... but I hope you can do it from here:

How do I extend a UIToolbar across landscape orientation in iOS7?

I have a UIToolbar set up in my view controller that has a width of 768, extending across portrait view as I desire. But when I rotate to landscape, the toolbar maintains the same width, instead of extending to 1024 pixels.
I'm probably missing something obvious, but I can't seem to figure this out. Any ideas? Thanks.
You need to add Horizontal Space constrains as below:

NSTabView with background color

As discussed elsewhere, NSTabView does not have a setBackgroundColor method and subclassing NSTabView and using an drawRect to control it does no longer work - as it does not paint the top 10%, the bit just below the segmented control button.
Now I am a bit surprised by the amounts of work arounds I had to do solving this; see
code: https://github.com/dirkx/CustomizableTabView/blob/master/CustomizableTabView/CustomizableTabView.m
and am wondering if i went down the wrong path. And how to do this better & simpler:
The NSSegmentStyleTexturedSquare seems to yield me a semi-transparent segmented Control. Which means I need to do extra work to hide any bezel lines (line 240, 253).
is there a better way to do this ? I.e. negate its transparency ?
or is there a way I can use the actual/original segmented choise button ?
I find that the colours I need - like the [NSColor windowBackgroundColour] are not set to anything useful (i.e. that one is transparent) -- so right now I hardcode them (lines 87, 94).
Is there a better way to do this ?
I find I need a boatload of fluffy methods to keep things in sync ( line 128, 134, etc).
can this be avoided ?
I find that mimicking the cleverness on rescaling means I need to keep a constant eye on the segemented Control box and remove/resize it. And even then - it is not quite as good as the original
is there a better way to do this than line 157 -- i.e. hear about resizing ? Rather than do it all the time ?
The segementControl fades dark when focus is removed from the window - unlike the real McCoy.
can that easily be prevented ? is there a cheap way to track this ?
Or is this the wrong approach - and should I focus on just a transparent hole here - and let the NSTabViewItem draw a background ? But in any case - then I still have the issue with the Segemented COntrol box - or is there than a way to make that be the default again.
when trying this - I get stuck on the top 20-30 pixels being drawn in the 'real' windows background colour - which is 'transparent' - and hence the colour will not run all the way to the top or behind the segment bar and up to the bezel - but instead stop some 8 pixels below the bottom of the segment controls.
Feedback appreciated - as this feels so far off/suboptimal for such a simple things --
Thanks a lot. Brownie points for hacking/forking the github code :) :) :) As a line of running code says more than a thousand words.
Dw.
PSMTabBarControl is probably the best workaround for you. I have created several custom tab views, but cocoa does not play well with this control. PSMTabBarControl has been updated to support Xcode 4. https://github.com/ciaran/psmtabbarcontrol
Have you tried setting the background color of its underlying CALayer? (Make it a layer-backed view, if it isn't already, by setting wantsLayer = YES.)
If your situation can tolerate some fragility, a very simple and quick approach is to subclass NSTabView and manually adjust the frame of the item subviews. This gives each item a seamless yellow background:
- (void)drawRect:(NSRect)dirtyRect {
static const NSRect offsetRect = (NSRect) { -2, -16, 4, 18 };
NSRect rect = self.contentRect;
rect.origin.x += offsetRect.origin.x;
rect.origin.y += offsetRect.origin.y;
rect.size.width += offsetRect.size.width;
rect.size.height += offsetRect.size.height;
[[NSColor yellowColor] set];
NSRectFill(rect);
[super drawRect:dirtyRect];
}
A future change in the metrics of NSTabView would obviously be a problem so proceed at your own risk!

NSWindow Content Border messing with CALayer's geometry

I have an NSWindow with a 32px bottom content border. Inside the window's view, I have two custom subviews. Each of them are layer backed, and I'm tracking the mouse with an NSTrackingArea. Part of what I'm doing is some mouseOver effects with CoreAnimation. This is not a problem in general, but I noticed something kind of strange and wondered if anyone knows why this is happening.
When setting up the trackingArea and mouseOver method, I hitTest the root layer and log the layer's name so I can see if the geometry of the various sublayers hold water when I resize the window. Internally, they seem (and look) fine. Visually, they are in the right place, but when I move the mouse, I notice that the though the mouse is physically over a layer, hitTest is returning whatever layer is 32 px above it. However, if I remove the content border, it works as you would expect and the correct layer is returned.
I obviously need the content border, so I have a very simple workaround which involves offsetting the hitTest point by 32px. This works fine, but it just seems weird that the presence of a content border seems to skewing the co-ordinate system of these subviews. Does anyone know why this could be happening?
NSEvent returns mouse locations relative to the window's coordinate system, not the targeted view's. You probably need to call convertRect:fromView: to get the correct coordinates.

Resources