Weird font behavior on the NSTextField - macos

I added programmatically NSTextField to my NSView:
NSTextField *projectLabel = [[NSTextField alloc] initWithFrame:frame];
[projectLabel setStringValue:#"projectName"];
[projectLabel setBezeled:NO];
[projectLabel setDrawsBackground:NO];
[projectLabel setEditable:NO];
[projectLabel setSelectable:NO];
[projectLabel setFont:[NSFont controlContentFontOfSize:13]];
projectLabel.autoresizingMask = NSViewMaxXMargin | NSViewMinYMargin;
[self addSubview:projectLabel];
[self setAutoresizesSubviews:NO];
This field was added correctly, but when I change size of view (or even move window to second display), font on field changes very weird (see attached image).
on start
after change of the size
I do not know what I did wrong

I drew this label on drawRect every time, when the size changes.
So, you're manually telling the field to display in its parent view's drawRect:?
Don't do that. It's a subview, so it'll get told to draw in its turn anyway. Just let that happen.

Related

How to make a MTKView inside a NSScrollView show the scrollbars

If I resize the window to be smaller than the metal view I can see the scrollbars for a second but I cannot click on them nor they stay visible. Do you know how I can change this behavior? I would expect the scrollbars to be visible and clickable as long as the window is smaller than the metal view.
nsview = gdk_quartz_window_get_nsview(window);
NSScrollView *scroll_view = [[NSScrollView alloc]initWithFrame: [nsview frame]];
[scroll_view setBorderType: NSNoBorder];
[scroll_view setHasVerticalScroller: YES];
[scroll_view setHasHorizontalScroller: YES];
[scroll_view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
[nsview addSubview: scroll_view];
self->clip_view = [[DvFlippedClipView alloc]initWithFrame: [nsview frame]];
[scroll_view setContentView: self->clip_view];
self->mtk_view = [[MTKView alloc]initWithFrame: [nsview frame]
device: self->device];
self->mtk_view.framebufferOnly = YES;
self->mtk_view.autoResizeDrawable = NO;
self->mtk_view.translatesAutoresizingMaskIntoConstraints = NO;
self->mtk_view_delegate = [[DvMetalViewDelegate alloc] init: self->mtk_view];
self->mtk_view.delegate = self->mtk_view_delegate;
[scroll_view setDocumentView: self->mtk_view];
From a different callback I do the following:
[self->mtk_view setBounds:NSMakeRect(0, 0, width, height)];
[self->mtk_view setFrame:NSMakeRect(0, 0, width, height)];
self->mtk_view.drawableSize = CGSizeMake(width, height);
I had a similar problem yesterday, and I suspect the strange scroller behavior and lack of scrolling altogether may be stemming from what I suspect your problem is. Hopefully it will at least enlighten your or someone else if you haven't already found an answer.
My view hierarchy looks like this:
The problem was that I had set MTKView as the view property of CenterTopViewController, rather than the Bordered Scroll View. Doing that, for all practical intents and purposes, removed MTKView from the hierarchy and set it so that its superview property pointed to the split view in which all of this resides. The scroll view did not seem to be part of the responder chain, and was never handling any scroll events (or at least not in any meaningful way).
Setting the scroll view as the view property of the view controller fixed everything.
P.S.
If you're confused as to why there is an unnecessary view above the MTKView, it's just a result of almost desperate attempts to uncover the problem before I figured it out. I haven't gotten around to fixing it yet.

setStringValue in NSTextField will always change height

I have a NSTextField in a view where layout is totally controlled by constraints and translatesAutoresizingMaskIntoConstraints is NO. I tried to use setStringValue to change the content like this:
[[self textfield] setStringValue:#"1\n2\n3\n"];
Then the height is changed to 4 lines which is not what I want. I need a NSTextField that can show only one line but still I can use up and down arrow keys to go into different lines. It is just like use option+enter to insert a newline in NSTextField.
I also tried to keep the height:
NSRect originalFrame = [[self textfield] frame];
[[self textfield] setStringValue:#"1\n2\n3\n"];
NSRect newFrame = [[self textfield] frame];
newFrame.size.height = originalFrame.size.height;
[[self textfield] setFrame:newFrame];
It doesn't work. I checked intrinsicContentSize and it returns (width=-1, height=73). Is there anything I can set to NSTextField so the height is of only one line like 22?
This is happening because you have set the auto layout of textfield with respect to the view. So just fixed the height of your textfield by clicking on the height checkbox like that below :-

NSTableView's frame inside a NSClipView/NSScrollView using auto layout

I'm trying to create a NSTableView inside a NSScrollView (the standard configuration, that is) in code, using auto layout. I can't figure out how to make this work.
Here's my loadView:
- (void)loadView
{
NSView *view = [[NSView alloc] init];
NSScrollView *tableScroll = [[NSScrollView alloc] init];
NSTableView *fileTable = [[NSTableView alloc] init];
[tableScroll setDocumentView:fileTable];
[tableScroll setHasVerticalScroller:YES];
[tableScroll setHasHorizontalScroller:NO];
fileTable.delegate = self;
fileTable.dataSource = self;
[fileTable setHeaderView:nil];
[fileTable setAllowsColumnReordering:NO];
NSTableColumn *column = [[NSTableColumn alloc] initWithIdentifier:#"column1"];
[fileTable addTableColumn:column];
[tableScroll setTranslatesAutoresizingMaskIntoConstraints:NO];
[fileTable setTranslatesAutoresizingMaskIntoConstraints:NO];
[view addSubview:tableScroll];
NSDictionary *topViews = NSDictionaryOfVariableBindings(tableScroll);
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[tableScroll]|" options:0 metrics:nil views:topViews]];
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|[tableScroll]|" options:0 metrics:nil views:topViews]];
self.fileTable = fileTable;
self.view = view;
}
What happens is that my table view's frame will be always equal to the bounds of the NSClipView. The view is inside a window and gets resized with it, and when I do that it'll resize the scrollview, the clip view and the table, but I can never scroll anywhere.
Looking at constraints I get, the NSScrollView gets constraints that set the clip view to fill it, the clip view has no constraints at all and the table view has a bunch of constraints related to the NSTableRowViews inside it.
If I add a constraint like |[fileTable(>=500)] to the clip view I'll get 500 pixels of NSTableView, but obviously I don't want to do that.
Even though this was answered by the poster in the comments above, I thought I’d put the answer here (having run into the same issue). If you are adopting auto layout, you would typically uncheck “Translates Mask Into Constraints” in the xib. However, for classes like NSScrollView and NSTableView, you should generally let them manage their own internal views by setting their translatesAutoresizingMaskIntoConstraints property to YES. It is still ok to set constraints that are external to these views, i.e. to resize in relation to their superview.
If you set translatesAutoresizingMaskIntoConstraints to NO, then you will need to supply constraints for all of the internal views, which unless you specifically need custom behavior (almost never), you will not want to do. This was the specific problem above.
An obvious side effect of not setting this correctly is that a table (for example) will not properly scroll beyond what is visible in the view.

Default NSRecessedBezelStyle NSButton visual bug?

I have a basic NSRecessedBezelStyle NSButton added via IB to an NSView. Why is the font messed up in its unselected state? Is this normal?
As you can see, when pushed the recessed button looks fine, but unpressed it's solid black with no shadow. Am I missing something really obvious somewhere? I tried messing around with setAttributedTitle and setAttributedAlternateTitle but that yielded odd results with the push on push off mechanic.
That is the expected behavior for NSRecessedBezelStyle with the default "Push On Push Off" Type, bezeled in On state, plain text in OFF, additionally you can change the Type so the bezel is only displayed when hovering, here is the code to make it gray.
NSMutableDictionary *attrsDictionary = [NSMutableDictionary dictionaryWithCapacity:1];
[attrsDictionary setObject:[NSColor grayColor] forKey:NSForegroundColorAttributeName];
[attrsDictionary setObject:[NSFont boldSystemFontOfSize:12.0] forKey:NSFontAttributeName];
NSMutableParagraphStyle *paragraph = [[[NSMutableParagraphStyle alloc] init] autorelease];
[paragraph setAlignment:NSCenterTextAlignment];
[attrsDictionary setObject:paragraph forKey:NSParagraphStyleAttributeName];
NSAttributedString *str = [[[NSAttributedString alloc] initWithString:#"Button" attributes:attrsDictionary] autorelease];
[button setAttributedTitle:str];

How do I get the inner/client size of a NSView subclass?

I am doing manual layouting for my Cocoa application and at some point I need to figure out what the inner size of a NSView subclass is. (E.g. What is the height available for my child view inside of a NSBox?)
One of the reasons is that I am using a coordinate system with origin at the top-left and need to perform coordinate transformations.
I could not figure out a way to get this size so far and would be glad if somebody can give me a hint.
Another very interesting property I would like to know is the minimum size of a view.
-bounds is the one you're looking for in most views. NSBox is a bit of a special case, however, since you want to look at the bounds of the box's content view, not the bounds of the box view itself (the box view includes the title, edges, etc.). Also, the bounds rect is always the real size of the box, while the frame rect can be modified relative to the bounds to apply transformations to the view's contents (such as squashing a 200x200 image into a 200x100 frame).
So, for most views you just use [parentView bounds], and for NSBox you'll use [[theBox contentView] bounds], and you'll use [[theBox contentView] addSubview: myView] rather than [parentView addSubview: myView] to add your content.
Unfortunately, there is no standard way to do this for all NSView subclasses. In your specific example, the position and size of a child view within an NSBox can be computed as follows:
NSRect availableRect = [someNSBox bounds];
NSSize boxMargins = [someBox contentViewMargins];
availableRect = NSInsetRect(availableRect, boxMargins.width, boxMargins.height);
If you find yourself using this often, you could create a category on NSBox as follows:
// MyNSBoxCategories.h
#interface NSBox (MyCategories)
- (NSRect)contentFrame;
#end
// MyNSBoxCategories.m
#implementation NSBox (MyCategories)
- (NSRect)contentFrame
{
NSRect frameRect = [self bounds];
NSSize margins = [self contentViewMargins];
return NSInsetRect(frameRect, margins.width, margins.height);
}
#end
And you would use it like so:
#import "MyNSBoxCategories.h"
//...
NSRect frameRect = [someNSBox contentFrame];
[myContentView setFrame:frameRect];
[someNSBox addSubview:myContentView];
The bounds property of NSView returns an NSRect with the origin (usually (0,0)) and the size of an NSView. See this Apple Developer documentation page.
I'm not sure (I never had to go too deep in that stuff), but isn't it [NSView bounds]?
http://www.cocoadev.com/index.pl?DifferenceBetweenFrameAndBounds

Resources