How to display elements inside NSCollectionView with various shapes - macos

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.

Related

NSWindow and text smoothing in NSTableView cell view

I'm writing an OS X app and have a problem with font smoothing in separate window.
I have a text field where you put text and suggestion window which pops up with a list of suggestions according to what you wrote. I'm using View-cell based NSTableView to display those suggestions and SFBPopoverWindowController to display it as a "popup" window (tried other classes with the same effect). When rows are first drawn they look fine but after I select them (keyboard or mouse) the font changes it's weight. It's only visual - like you would change smoothing method on the font, not it's bold setting.
"Music note" is the selected cell here
What's even more strange is that after I hide and show the window 3 times everything works fine from that point on.
Again - "Music note" is the selected cell.
The selection is done by overwriting NSTableRowView class and its drawSelectionInRect: method but I tried with drawing everything inside custom NSTableCellView class and it didn't help. The text is standard NSTextField - nothing's changed there.
The SFBPopoverWindow (and it's controller) are created once and reused with styleMask NSBorderlessWindowMask, backing NSBackingStoreBuffered, defer set to YES. The only change in SFBPopoverWindowController I made was to turn off window becoming key window but it doesn't change anything.
It might be related to the way a table view draws it's selected cells (setSelectionHightLightStyle:). Try to set the style to None/ NSTableViewSelectionHighlightStyleNone in your code or IB / Storyboard-file and draw the selection yourself (in a NSTableRowView subclass).
Background: When you use NSTableViewSelectionHighlightStyleRegular or NSTableViewSelectionHighlightStyleSourceList the table view assumes that you use the standard selection behaviour and appearance and does some magic to support that.
==========
UPDATE
==========
My previous answer is still valid but since it only describes the problem and hints at a workaround, I wanted to add a real solution. If you want to use NSTableViewSelectionHighlightStyleRegular for your table view (with custom font and colors), you need a way to 'disable' the system magic that comes into place once your row is highlighted. One proposed solution is to decline the first responder status. It has a lot of drawbacks and isn't a good solution at all.
So, let's have a closer look at the system 'magic' that kicks in as soon as the row will be highlighted: NSTableRowView has a property interiorBackgroundStyle that is – according to the documentation – 'an indication of how the subviews should draw'. Furthermore 'This value is dynamically computed based on the set of properties set for the NSTableRowView. Subclassers can override this value when they draw differently based on the currently displayed properties. This method can also be called to determine what color a subview should use, or alternatively, NSControls can have the -backgroundStyle set on their cell to this value.'
I assume that this style will be handed down the subview hierarchy and causes your text fields to look odd. The system assumes that a highlighted cell has a dark background and changes the interiorBackgroundStyle to dark. Other controls try to adapt accordingly.
I think there are two solutions to this problem:
1) Override interiorBackgroundStyle in your NSTableRowView subclass and return the style that fits your interface (in my case it's .light because my highlight color is a very bright blue). This worked for me.
2) If changing the whole style is a bit too much because you only want certain elements to not change their style, you may only need to adjust these subclasses. I haven't tried this yet.

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.

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

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.

NSLevelIndicator with text on It?

How can I add text on top of a NSLevelIndicator? [the NSLevelIndicator is in my statusbar, if that matters]
The best way to add text to your NSLevelIndicator user interface is by adding a separate Label NSTextField. The NSLevelIndicator control does not have a title or other text associated with it.
From within Interface Builder, just grab a Label and drag it to your window above or beside the NSLevelIndicator.
Contrary to the correct answer to your previous question, if you want to use an NSLevelIndicator as a background and draw text on top of it, you're better off creating a custom view that owns and uses an NSLevelIndicatorCell for the background drawing.
You might also consider drawing the background yourself; e.g., fill with your choice of green/yellow/red, and then draw a white gradient on top of it. This is more appropriate if you're not really indicating a level with your level indicator.
Also, don't forget to test your application with Sim Daltonism, to make sure that the text is still readable to color-blind users.

make NSRect selectable

Is there a simple way to create a selectable NSRect in Cocoa? In need a rectangle that can be selected and stays selected after a mouse click.
Thanks.
NSRect is just a struct with a position and size. It's not an object that can actually do anything or have any properties other than a width and height. It sounds like what you want is to create an NSView that can be selected. (Here's Apple's Guide on the subject.)
Though not as immediate as you would like, you may be interested in the management of tracking rectangles and tracking areas performed by NSView class.
This mechanism allows you to define specific areas of your custom view. Then, an event is generated whenever the cursor enters or leaves the area, or a mouse button is pressed in this area (-mouseEntered:, -mouseExited:, -mouseDown:, -mouseUp:, -mouseDragged:, ... of NSResponder class). This up to you to define what you want your application do in response to these events (set the rectangle as selected and display it accordingly).
For an example implementation of this, take a look at the Sketch example included with the Apple developer tools (look in /Developer/Examples/AppKit). Sketch allows the user to create new graphics (including rectangles, but also ovals, lines, and text), select them, move them around in the document, etc. In particular, you'll probably want to look at the SKTGraphic class, which represents a single graphic object in the document, and the SKTGraphicView class, which is an NSView subclass that perform the actual layout and drawing, handling mouse events for dragging views around, etc.

Resources