I`ve got several programmatically created NSTextField-s, used as static text controls. The algorithm that creates them sets their dimensions via setFrame: and assumes that they have zero padding between the text and the upper right corner of the control, which is not the case, so the text is getting clipped.
At first I began researching the topic of zero padding for NSTextField-s but quickly realized that this approach requires subclassing. It would be much easier for me than that if I could just use some method to obtain the padding dimensions and adjust the bounding rectangle accordingly.
My question is: what`s the name of that method?
[UPD:] Seems to be alignmentRectInsets, however it`s not available on macOS 10.6 — so I`d like to know if there is a similar method for 10.6.
Related
How can I get the current position of a CALayer instance in the coordinates of its super layer? (Mac application)
I would have expected this to be available from the frame property but it isn't. In particular, this CALayerinstance has been positioned using various CAConstraint types and I have not specified the (x,y) position explicitly.
The problem seems to have gone away when I check the frame "later" during the execution of the program.
In the question I was checking the bounds during the init and I can thus assume that the actual layout had not taken place yet and hence the runtime didn't know what the position actually was - it was indeterminate at that point.
Bear with me on this one, as it's been frustrating me for a few days. This seems like it should be really simple, but for some reason I keep running into a series of frustrating problems. I've done more work on iOS in the past, and never had these kinds of problems that I'm having on OS X. I'm wondering if I'm not understanding something fundamental about the view architecture in AppKit. In particular, I am not very familar with the interaction between layer-backed views and plain views as I have not needed to animate anything on OS X before (and because iOS makes all views layer-backed by default).
Anyway, I'm having some major problems with trying to rotate an NSTextView object by 45 degrees. The text is for some labels that get placed in a larger custom NSView subclass, but most of that seems irrelevant to this specific problem. I'll go through what I've tried and the problems I had. The position of the labels is basically static, so I don't care about whether or not they are animatable or not. The labels need to be created and placed programmatically, not from IB, as their size and position is dependent on dynamically generated data. If it matters, the NSTextViews are using attributed strings.
1) I first did this the way that seemed most straightforward to me, which was simply to set frames for the NSTextView labels, added them as subviews to the graph object, and then called [labelTextView setFrameRotation:45] on them. This worked perfectly on Mountain Lion, but when I tested it on Lion the label height that gets drawn on screen gets increased mysteriously (even though when I log the frame afterwards it is unchanged). That isn't acceptable because I need it to draw a background color for the label so that it looks readable when overlaid onto the graph. So on Lion there is a bug or something in setFrameRotation as applied to NSTextView (or so it would seem). Does anyone know what is going on with that? It's very annoying that it works correctly on 10.8 but not on 10.7. SetFrameCenterRotation has the same problem. Making the view layer-backed, or not, seems to make no difference.
2) I next tried to do this using CATransform3DMakeRotation, after making the parent view and the NSTextView layer-backed. I used the line labelTextView.layer.transform = CATransform3DMakeRotation(M_PI_4, 0, 0, 1.0);, but the text view doesn't rotate when I do this. As a test, I tried the same thing using a plain NSView with a colored background, and it does rotate correctly. Does anyone know possible reasons why this wouldn't work with an NSTextView?
3) I tried enclosing the NSTextView in a NSView container and then calling setFrameRotation on that. This does rotate it correctly, but somehow triggers an infinite recursion in Core Animation that quickly consumes gigabytes of RAM unless I kill the process! Again, any ideas about what's going on there?!?
4) I tried all of this using Autolayout to position the labels AND positioning them manually by setting their frames. No differences in results either way.
5) I could do this using completely custom drawing, but that would be a LOT of work in this particular case. I'd rather not do that just to support 10.7. I also could try NSTextField to see if it suffers from the same thing in part 1), but that would be annoying because I want some of the features of NSTextView (this isn't just a single line blob of text).
What am I doing wrong here? I never imagined something this simple being this difficult to get working correctly on 10.7 + 10.8.
UPDATE:
I tried substituting NSTextField for NSTextView and the problem in 3) goes away (the paragraph styling isn't exactly how I want it yet, but I can possibly fix that). Any ideas on why NSTextView has such problems with being rotated where NSTextField apparently doesn't? That seems insane to me. I'll try NSTextField without the container next to see if it also suffers from the drawing glitch on Lion.
UPDATE 2:
I tried just using an NSTextField instead of an NSTextView and rotating it, and that also worked completely fine on both Lion and Mountain Lion. The visual glitch where the size of the text view changes after rotation also disappears. So I guess the answer is that NSTextView is just totally incapable of having its frame rotated without triggering multiple bugs (especially on older versions of OS X). If that's the case, and NSTextView isn't intended to be used that way, Apple's docs should probably say so. Can anyone confirm that that is the case?
I'm trying to solve this problem for a week now and I have tested a lot of ideas that I had on my mind but I'm unable to properly calculate size of the NSString with custom font.
I have UITextView which contains text and one UIView on which I draw line numbers for the lines in UITextView. The problem is that NSString UIKit Additions are ignoring tab width in calculation of size of the NSString.
Here on picture you can see that clearly on line 7, which is line with line break when rendered in UITextView, and after that all lines are affected.
Font that I'm using is Adobe Source Code Pro.
I have tried all methods from NSString UIKit Additions without success.
sizeWithFont
sizeWithFont:forWidth:lineBreakMode:
sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode:
I have also tried to replace all tabs in string with four spaces, it helps, but still it doesn't work all the time. For some lines it helps but for some it doesn't.
Any suggestions how to calculate NSString height properly? CoreText maybe?
One small note. I have tried to solve this also with using Geometry hit testing methods from UITextInput Protocol and while they are working, cpu load is 100% on simulator, so on real device it's going to kill the app, specially if I load file that is about 1500+ lines of code.
And here is the gist with code that I'm using for LineNumbersView.m.
Assuming UITextView and Core Text always exactly agree then the latter is definitely a solution, though it's not desperately straightforward for this problem.
You'd:
create an attributed string of the text in the main view, having set the appropriate font across the entire range;
create a suitable framesetter for the attributed string (using CTFramesetterCreateWithAttributedString);
create a CGPath that describes the drawing area that the string will be drawn to (either as a UIBezierPath and then getting the CGPath property or by creating one and using CGPathAddRect);
hence create a frame from the framesetter plus the path plus the subrange of the string you're interested in, which will likely be all of it (see CTFramesetterCreateFrame);
from the frame you can then obtain a CFArray of the individual lines it would output (using CTFrameGetLines), though these are the on-screen typeset lines rather than your source lines;
for each line you can get the range of the original string that it contains (using CTLineGetStringRange), allowing you to determine which begin immediately after your original newline characters rather than due to word wrap;
you can also get a C array of CGPoints where each represents the origin of an on-screen line (CTFrameGetLineOrigins); by using what you learn in (6) to look up positions in that you can get the on-screen origins of the relevant lines.
For added fun, the pixel output of Core Text is identical on OS X and on iOS. However OS X considers the screen's original to be the lower left corner, like graph paper. iOS considers it to the top left corner, like English reading order. The roughly worded net effect is that on iOS Core Text draws upside down. So you'll need to take that into account. In iOS terms you'll apparently see the first line as being at the very bottom of your frame, the second as being one line above that, etc. You'll need to flip those coordinates.
It'll probably end up being just a hundred or so lines of code even though you're jumping through so many hoops.
I have some graphics that is already scaled and cut correctly for my project.
I choose to build the UI in IB and positioned everything correctly, under size and position I left it a "Frame" (instead of layout).
At runtime my graphics is moved and stretched according to which UIViewContentMode I set.
If I was doing this completely in code and set a frame and no UIViewContentMode, Cocoa would respect this and leave the graphics alone. However IB does things a bit different.
I think my problem is that I don't precisely understand what the different UIViewContentMode's does and I can't find the correct one to "turn off" the manipulation of the graphics at runtime.
Can someone give my a little help on this one:)
Thanks in regards.
If you don't set the value, the default is UIViewContentModeScaleToFill. If doing it in code and then calling setNeedsDisplay does it "scale to fill"? I think it depends on how you "do it in code" when the content mode is enforced - I assume IB is doing some extra stuff in the init to apply the content mode that you are not doing in code.
Anyway, if you don't want it to "scale" you can pick any of the UIViewContentMode operations that don't have the word "Scale" in the name. Review the UIViewContentMode enum for details on what each one does.
If i wanted to crop an image in VB.net, how would I go about doing it? I am trying to let the user drag out the box they want (system.drawing.rectangle), and it will automatically remove the edges surrounding the box.
My first problem is primarily the fact that I cannot make the system.drawing.rectangle visible. It is not displaying at all, I am setting its location and height programmatically, but nothing is showing up. I know there is probably something fairly obvious I am missing...but I cannot seem to find it.
My larger issue, however, lies with the cropping itself. I cannot find any crop methods, at all. Is there a hidden one I am missing? Or must I code it myself? How would I go about doing this? It ought to be able to output to a bitmap image object.
Thanks for the help, I am surprised this hasn't been asked on here before....
Regarding your first problem: a Rectangle isn't by itself visible. You have to draw it on your canvas using the Graphics object's DrawRectangle(...) method. For drawing a selection tool, you'll want to set your Pen object's DashCap and DashPattern properties.
To "crop" an image, you basically want to take the portion of a larger image delineated by a smaller Rectangle, and turn it into a new Bitmap. This can be done using one of the 30 overloads of the Graphics object's DrawImage(...) method. You can either keep the cropped portion in its original dimensions (resulting in a smaller Bitmap than your original), or you can "blow it up" to something like the original image's size. If you do the latter approach, it is usually a good idea to set your Graphics object's InterpolationMode property to HighQualityBicubic (I think that's the one, anyway), since the default InterpolationMode is pretty crappy.
There are a number of different ways of rendering images in .Net - it might help if you posted some of your code, along with an explanation of the exact problems you're running into.
Here is another answer with a link to a sample app (and source code in C#, sorry) that may help you get started.
There are a number of articles on these topics on CodeProject:
Pick your favorite flavor (though I encourage you to check out the C# projects - it shouldn't be too hard to convert).
VB
Image Cropping with Image Resizing Using vb.net
C#
Cropping Images
An Easy to Use Image Resizing and Cropping Control
Image Processing using C# (see the Cropping section - I was able to use this code in one of my projects)
WPF/C#
WPF Interactive Image Cropping Control
A Photoshop-like Cropping Adorner for WPF