How can I get an NSTextField to behave like a HTML text? - cocoa

I have some static text that is usually only 1 line long that displays in a NSTextField in my xib. In some instances, the text is long enough to warrant 2 lines, and I just want the label to resize vertically to fit it, without giving me scrollers or any thing else. Think of how text on a webpage behaves… that is what I want. I just want the label to grow shrink with different text, and with adjustments to its width. How can I achieve this?
UPDATE
Here is a video of how it currently behaves: http://screencast.com/t/4JYTv7jVG3O
Notice how when the NSTextField is two lines long, there is a big gap underneath the text. This is because the stars and button are aligned at the bottom of the frame, and because I have to have the frame taller to accommodate 2 lines, they stay there. If I can get an answer to this question, I would make the frame shorter for the 1 line text, and make the bottom textfield (with the smaller text) taller to compensate. Can this type of floating layout be done?

One option is to actually use a WebView to display your content. You will then get exactly the behaviour you are expecting, at the cost of a bit of work to manage interaction with the controls.
You would need to set the WebView to display no background, using [webView setDrawsBackground:NO].
You'd also need to construct the content (including the star rating and the button) using HTML/CSS and then use the Objective-C/JavaScript bridge to call back to your app when the button is pressed.
More information on calling Objective-C from JavaScript is here.
You could probably also use an NSTextView and embed the button and star rating as NSTextAttachment objects but this is quite complex, it would be a lot easier to use a WebView.
The only other alternative that I can see is writing a view controller that manages the layout of the controls based on the current size of their container view. You would need to measure the text to do this and one way to do that is to use the excellent NS(Attributed)String+Geometrics category written by Jerry Krinock.

Related

How to display elements inside NSCollectionView with various shapes

I am a rookie Cocoa guy. I need to design and implement a view which will show collection of labels on Mac OS using Xamarin. These labels will have a text and color associated with them. When shown inside the view, label should expand till it covers whole text and it will be shown with background and foreground colors.
I have attached the picture of this user control on Windows, you can see that labels inside the StackPanel are expanding till they cover the whole text. Hope this gives better idea about my ask.
The $64,000 question is "are these labels controls?" In other words, do you expect the user to click on these to do something, or are they just for display?
If your answer is "just for display", the solution is super simple: Use an NSTextField and programmatically add attributed text (NSAttributedString) to it. Attributed text attaches display properties to runs of text within the field; properties like "background color".
If you want these to be buttons that you can click on, then things get a lot more complicated.
Since you apparently want the button layout to "flow", you might look into imbedding buttons (well, button cells) into an NSTextField using attachments. This is normally how non-text content (say, an image) can be inserted, but with some fiddling it can actually be anything a control cell can draw. See How to insert a NSButton into a NSTextView? (inline).
Warning: this is not a "rookie" topic and will involve control cells and custom event handling.
If I were doing this, I'd probably just create NSButton objects for each label (choosing an appropriate style/look like NSRecessedBezelStyle), create a custom subclass of NSView to contain them, and then override the layout method to position all of the buttons the way I want.
To be thorough, I'd also override the intrinsic size methods so the whole thing could participate in auto-layout, based on the number and size of buttons it contained.

Seeking a simple Mac OS NSTextView example using AutoLayout

After much reading and experimenting, I still cannot get a simple TextView to resize fully in the horizontal direction using Xcode 5.0.2 in Mavericks. It resizes partially as the window is resized, then stops with long lines wrapped around even though my containing NSScrollView continues to resize as expected (it has four default constraints and no horizontal scroller).
Can anyone point me to a simple code/IB+AutoLayout example, preferably just a window containing just an NSTextView dragged in from the IB template library --- one that works? The Apple TextEdit sample code is almost irrelevant for this purpose although it does resize horizontally quite well. Also, there is the clip view for which I can find little information.
Any other tips appreciated.
Thanks.
Answering my own question:
Turns out that my problem had nothing to do with AutoLayout and little to do with NSTextView. It was the textfile I was using to test my code! This file was composed of records with tab-delimited fields.
Turns out that NSTextView comes with a default NSParagraphStyle with predefined tab stops that end at character 56 whereas my test file had tabs beyond that. Therefore, my lines wrapped around at the last defined tab no matter how much I stretched the window.
After changing my search terms, I found what I needed at the following links:
Premature line wrapping in NSTextView when tabs are used
How to have unlimited tab stops in a NSTextView with disabled text wrap
Apologies for wasting bandwidth.
Not sure why such a simple thing does not work in your case, but nevertheless here's what I did in Xcode to get an NSTextView follow window resize:
Create a new project (not document based in my case but it doesn't really make a difference)
Drag a NSTextView from the palette to your window. Align all four edges with the window edges.
Open the "Add constraints" pop-up (second button from the segmented control on the bottom-right part of your IB view.
Each of the four spacing constraints should show a number equal to the distance of your text view from the container window. If you aligned them, this number should be either 0 or -1. Click the down arrow for each of them and select "Use Current Canvas Value". Do it for all four. Make sure no other constraints are selected.
Click on "Add constraints" on the bottom of the panel.
Run your project. Your textview should resize with the window.
Also, as Jay's comment mentions, make sure you do not have any "leftover" constraints in your view. You can check this either by observing Xcode's warnings, or manually by inspecting your view's constraints by going to the Size Inspector tab (4th tab on the Utilities bar).
If you need to have your textview arranged in a more complex layout, it might be worth taking a look at the AutoLayout Guide.

Adding controls to NSTextView and binding them to (ranges of) characters

When editing code, Xcode is capabale of displaying in-text controls, like drop down buttons which can show context menu's. I've seen other OS X apps that handle text capable of similar features. See the attached sample.
I presume this effect is obtained using NSTextAttachmentCell - although I'm not sure whether this is the proper way to implement this.
For my own app I would like to use this technique as well.
I have the following questions:
Is NSTextAttachmentCell the correct way to implement such a feature? If not, what would be?
How do I attach a control -comparable to the one in the above sample- to a specific range of text so that its location within NSTextView is dynamic and follows layout actions?
I found this which gives some hints but does not cover the attachment to specific text ranges.
Although NSTextAttachmentCell will work, it has a disadvantage: the cell will become just a glyph in the text which was not what I wanted. It distorts the layout of the text, is selectable etc. I wanted the cell to be drawn over the text, just like the behaviour in Xcode.
The challenge was to find a way of translating a point from a Mouse Moved event to the position of a particular string of characters inside the NSTextView.
After some more digging I found a little gem in Apple's demo apps called LayoutManagerDemo. This demo shows a custom subclass of NSTextView capable of highlighting individual characters, words and lines while the mouse is hoovering its view. From there on it was pretty easy to fade in a button at the required NSPoint and then show a popup menu with some options.

Padding around an NSTextView in an NSScrollView

I'd like to provide a few pixels of padding around an NSTextView inside of an NSScrollView. I've reviewed this post and using setTextContainerInset does the trick for the left, right, and bottom margins. But as soon as the text scrolls the top buffer is lost. Same thing with overriding textContainerOrigin. Another answer in that post states:
The way TextEdit does it (when in Wrap to Page mode) is to put the text view inside of a larger view, and set that larger view as the document view of the scroll view.
But if I do that (using, say an NSBox) the content no longer scrolls. Am I missing something regarding that particular trick, or are there any other techniques that folks could suggest?
There's a step that seems to be missing from your quote. You'll need to make sure your new document view tracks the changes in the text view's frame and sizes itself to fit. You can turn on NSViewFrameDidChangeNotification on your text view with -setPostsFrameChangedNotifications:, then have your new document view listen for notifications from your text view..
By the way, I ended up accomplishing this by subclassing NSClipView, overriding setFrame:, setFrameOrigin:, and setFrameSize, and hacking the origin and width in those methods to add my padding.

NSTextField on top of custom drawing - black outline and cursor not blinking?

I'm completely stumped with this problem. I made a custom search control that uses a few different classes. For some reason, when an NSTextField is anywhere over these different pieces, it displays a solid black border around it, and the cursor doesn't blink.
If anyone has a couple minutes - I've put together my code on pastebin.
Here's a picture of the search control, and what it looks like in this particular case:
The search control is sitting on top of a gradient view:
http://pastebin.com/m43fde2b6
The search control is pieced together with this code:
http://pastebin.com/m5be08c32
The actual graphical part of the search control is built from two classes:
http://pastebin.com/m5bfa9439
http://pastebin.com/m5e909a2f (extends above class)
I cannot find what the heck is wrong. The text works, but there's a black border, and the cursor doesn't blink. What am I doing wrong?
Arg, I've been pulling my hair out for days on this one.
Putting one view over a sibling view has never been well-supported in Mac OS X. Try making it a subview instead. You may even want to make it a private component of a dedicated search-field view.
On that note, is there a reason you're not using NSSearchField?
I got it figured out! Finally.
What I didn't realize was the the "drawRect:" method's parameter "dirtyRect", is the portion of the control that is "dirty", meaning it needs to be redrawn.
So, when an NSTextField is on top of a control, it will trigger that control's "drawRect:" to be called (3) different times - with different "dirtyRect" parameters.
1: the cursor - usually an NSMakeRect(textField.origin.x,textfield.origin.y,1,textfield.origin.height).
2: the text field frame
3: the size of the control the text field is sitting on.
So, the fix was simple, change my control's scale 9 drawing to always draw to [self frame]. You can see the change here: http://pastebin.com/m50a5b0ad (line 89).
Previously, it was drawing to the "rect" parameter (http://pastebin.com/m5e909a2f - line 88), but depending on where the drawRect call was coming from, the rect parameter was different sizes.

Resources