How to use NSString drawInRect to center text? - objective-c

How can I draw a NSString centered within a NSRect?
I've started off with: (an extract from the drawRect method of my custom view)
NSString* theString = ...
[theString drawInRect:theRect withAttributes:0];
[theString release];
Now I'm assuming I need to set up some attributes. I've had a look through Apple's Cocoa documentation, but it's a bit overwhelming and can't find anything for how to add paragraph styles to the attributes.
Also, I can only find horizontal alignment, what about vertical alignment?

Vertical alignment you'll have to do yourself ((height of view + height of string)/2). Horizontal alignment you can do with:
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
style.alignment = NSTextAlignmentCenter;
NSDictionary *attr = [NSDictionary dictionaryWithObject:style forKey:NSParagraphStyleAttributeName];
[myString drawInRect:someRect withAttributes:attr];

This works for me for horizontal alignment
[textX drawInRect:theRect
withFont:font
lineBreakMode:UILineBreakModeClip
alignment:UITextAlignmentCenter];

Martins answer is pretty close, but it has a few small errors. Try this:
NSMutableParagraphStyle* style = [[NSMutableParagraphStyle alloc] init];
[style setAlignment:NSCenterTextAlignment];
NSDictionary *attr =
[NSDictionary dictionaryWithObject:style
forKey:NSParagraphStyleAttributeName];
[myString drawInRect:someRect withAttributes:attr];
[style release];
You'll have to create a new NSMutableParagraphStyle (instead of using the default paragraph style as Martin suggested) because [NSMutableParagraphStyle defaultParagraphStyle] returns an NSParagraphStyle, which doesn't have the setAlignment method. Also, you don't need the string #"NSParagraphStyleAttributeName"—just NSParagraphStyleAttributeName.

This works for me:
CGRect viewRect = CGRectMake(x, y, w, h);
UIFont* font = [UIFont systemFontOfSize:15];
CGSize size = [nsText sizeWithFont:font
constrainedToSize:viewRect.size
lineBreakMode:(UILineBreakModeWordWrap)];
float x_pos = (viewRect.size.width - size.width) / 2;
float y_pos = (viewRect.size.height - size.height) /2;
[someText drawAtPoint:CGPointMake(viewRect.origin.x + x_pos, viewRect.origin.y + y_pos) withFont:font];

[NSMutableParagraphStyle defaultParagraphStyle] won't work use:
[NSMutableParagraphStyle new]
also, it appears horizontal alignment only works for drawInRect, not drawAtPoint (ask me how I know :-)

For anyone interested in an iOS7+ adaptation, drop this in an NSString category:
- (void)drawVerticallyInRect:(CGRect)rect withFont:(UIFont *)font color:(UIColor *)color andAlignment:(NSTextAlignment)alignment
{
rect.origin.y = rect.origin.y + ((rect.size.height - [self sizeWithAttributes:#{NSFontAttributeName:font}].height) / 2);
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
[style setAlignment:alignment];
[self drawInRect:rect withAttributes:#{
NSFontAttributeName : font,
NSForegroundColorAttributeName : color,
NSParagraphStyleAttributeName : style
}];
}

For iOS Swift,
To center String within the rectangle using the method draw(in:withAttributes:)
func drawInCenter(_ text: String, into rectangle: CGRect, with textFont: UIFont) {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
let rectangle = CGRect.zero
paragraphStyle.minimumLineHeight = rectangle.height / 2 + textFont.lineHeight / 2
let textAttributes = [NSAttributedString.Key.font: textFont,
NSAttributedString.Key.paragraphStyle: paragraphStyle] as [NSAttributedString.Key : Any]
(text as NSString).draw(in: rectangle, withAttributes: textAttributes)
}

Well, drawInRect is only good for basic text drawing (in other words, the system decides where to position your text) - often the only way to draw text positioned where you want is to simply calculate what point you want it at and use NSString's drawAtPoint:withAttributes:.
Also, NSString's sizeWithAttributes is hugely useful in any positioning math you end up having to do for drawAtPoint.
Good luck!

The correct answer is:
-drawInRect:withFont:lineBreakMode:alignment:
I also created a small category for vertical alignment. If you like to use it, go ahead :)
// NSString+NSVerticalAlign.h
typedef enum {
NSVerticalTextAlignmentTop,
NSVerticalTextAlignmentMiddle,
NSVerticalTextAlignmentBottom
} NSVerticalTextAlignment;
#interface NSString (VerticalAlign)
- (CGSize)drawInRect:(CGRect)rect withFont:(UIFont *)font verticalAlignment:(NSVerticalTextAlignment)vAlign;
- (CGSize)drawInRect:(CGRect)rect withFont:(UIFont *)font lineBreakMode:(NSLineBreakMode)lineBreakMode verticalAlignment:(NSVerticalTextAlignment)vAlign;
- (CGSize)drawInRect:(CGRect)rect withFont:(UIFont *)font lineBreakMode:(NSLineBreakMode)lineBreakMode alignment:(NSTextAlignment)alignment verticalAlignment:(NSVerticalTextAlignment)vAlign;
#end
// NSString+NSVerticalAlign.m
#import "NSString+NSVerticalAlign.h"
#implementation NSString (VerticalAlign)
- (CGSize)drawInRect:(CGRect)rect withFont:(UIFont *)font verticalAlignment:(NSVerticalTextAlignment)vAlign {
switch (vAlign) {
case NSVerticalTextAlignmentTop:
break;
case NSVerticalTextAlignmentMiddle:
rect.origin.y = rect.origin.y + ((rect.size.height - font.pointSize) / 2);
break;
case NSVerticalTextAlignmentBottom:
rect.origin.y = rect.origin.y + rect.size.height - font.pointSize;
break;
}
return [self drawInRect:rect withFont:font];
}
- (CGSize)drawInRect:(CGRect)rect withFont:(UIFont *)font lineBreakMode:(NSLineBreakMode)lineBreakMode verticalAlignment:(NSVerticalTextAlignment)vAlign {
switch (vAlign) {
case NSVerticalTextAlignmentTop:
break;
case NSVerticalTextAlignmentMiddle:
rect.origin.y = rect.origin.y + ((rect.size.height - font.pointSize) / 2);
break;
case NSVerticalTextAlignmentBottom:
rect.origin.y = rect.origin.y + rect.size.height - font.pointSize;
break;
}
return [self drawInRect:rect withFont:font lineBreakMode:lineBreakMode];
}
- (CGSize)drawInRect:(CGRect)rect withFont:(UIFont *)font lineBreakMode:(NSLineBreakMode)lineBreakMode alignment:(NSTextAlignment)alignment verticalAlignment:(NSVerticalTextAlignment)vAlign {
switch (vAlign) {
case NSVerticalTextAlignmentTop:
break;
case NSVerticalTextAlignmentMiddle:
rect.origin.y = rect.origin.y + ((rect.size.height - font.pointSize) / 2);
break;
case NSVerticalTextAlignmentBottom:
rect.origin.y = rect.origin.y + rect.size.height - font.pointSize;
break;
}
return [self drawInRect:rect withFont:font lineBreakMode:lineBreakMode alignment:alignment];
}
#end

The following snippet is useful for drawing a center text string using an Annotation custom image as a reference:
CustomAnnotation.h
#interface CustomAnnotation : MKAnnotationView
[...]
CustomAnnotation.m
[...]
- (void)drawRect:(CGRect)rect
{
ClusterAnnotation *associatedAnnotation = (CustomAnnotation *)self.annotation;
if (associatedAnnotation != nil)
{
CGContextRef context = UIGraphicsGetCurrentContext();
NSString *imageName = #"custom_image.png";
CGRect contextRect = CGRectMake(0, 0, 42.0, 42.0);
CGFloat fontSize = 14.0;
[[UIImage imageNamed:imageName] drawInRect:contextRect];
NSInteger myIntegerValue = [associatedAnnotation.dataObject.myIntegerValue integerValue];
NSString *myStringText = [NSString stringWithFormat:#"%d", myIntegerValue];
UIFont *font = [UIFont fontWithName:#"Helvetica-Bold" size:fontSize];
CGSize fontWidth = [myStringText sizeWithFont:font];
CGFloat yOffset = (contextRect.size.height - fontWidth.height) / 2.0;
CGFloat xOffset = (contextRect.size.width - fontWidth.width) / 2.0;
CGPoint textPoint = CGPointMake(contextRect.origin.x + xOffset, contextRect.origin.y + yOffset);
CGContextSetTextDrawingMode(context, kCGTextStroke);
CGContextSetLineWidth(context, fontSize/10);
CGContextSetStrokeColorWithColor(context, [[UIColor whiteColor] CGColor]);
[myStringText drawAtPoint:textPoint withFont:font];
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextSetFillColorWithColor(context, [[UIColor blackColor] CGColor]);
[myStringText drawAtPoint:textPoint withFont:font];
}
}

Related

Dynamic collection view cell size-objective c?

I am working on collection view in objective c,
My problem was
1.I want to change the cell size according to it's content size
2.If there are no image in cell then like and comment view should go above(refer image).
I have changed the constraint like
NSLayoutConstraint *newConstraint;
if([image isEqualToString:#"no_image.jpg"] || [image isEqualToString:#"no_image.jpg"]){
cell.desc_ImgViewWidth.constant = 0;
[cell.Descimgview setHidden:YES];
newConstraint = [NSLayoutConstraint constraintWithItem:(cell.bottomConstraint).firstItem attribute:(cell.bottomConstraint).firstAttribute relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:(cell.bottomConstraint).secondItem attribute:(cell.bottomConstraint).secondAttribute multiplier:(cell.bottomConstraint).multiplier constant:(cell.bottomConstraint).constant];
}
else{
cell.desc_ImgViewWidth.constant = 120;
[cell.Descimgview setHidden:NO];
newConstraint = [NSLayoutConstraint constraintWithItem:(cell.bottomConstraint).firstItem attribute:(cell.bottomConstraint).firstAttribute relatedBy:NSLayoutRelationEqual toItem:(cell.bottomConstraint).secondItem attribute:(cell.bottomConstraint).secondAttribute multiplier:(cell.bottomConstraint).multiplier constant:(cell.bottomConstraint).constant];
}
[cell.contentView removeConstraint:(cell.bottomConstraint)];
[cell.contentView addConstraint:newConstraint];
[cell layoutIfNeeded];
[[cell contentView] setFrame:[cell bounds]];
[[cell contentView] setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
in cellForItemAtIndexPath delegate method.(like and comment view moving above at first, but after reloading the cell again i.e, like scrolling etc the constraint is not working perfectly)
I want to move like and comment view like this and to reduce the cell height for that particular cell(refer below image)
How to properly do this?
You can use UICollectionViewLayout
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
if imageView != nil
{
return CGSizeMake(width, height)
}
else
{
return CGSizeMake(width, height)
}
}
Finally achieved like this,
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary* object = [_Data objectAtIndex:indexPath.item];
NSString *image = [object valueForKey:#"image"];
if([image isEqualToString:#"no_image.jpg"] || [image isEqualToString:#"no_image.jpg"]){
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
float cellWidth = screenWidth;
NSDictionary* object = [_Data objectAtIndex:indexPath.item];
NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:[SwiftHelper getEmojiText:[object valueForKey:#"description"]]];
[str addAttribute:NSFontAttributeName value:[UIFont fontWithName:#"Georgia" size:15.0] range:NSMakeRange(0, str.length)];
CGSize sizeName = CGRectIntegral([str boundingRectWithSize:CGSizeMake(cellWidth-8, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin context:nil]).size;
NSMutableAttributedString *str1 = [[NSMutableAttributedString alloc] initWithString:[SwiftHelper getEmojiText:[object valueForKey:#"name"]]];
[str1 addAttribute:NSFontAttributeName value:[UIFont fontWithName:#"Georgia" size:15.0] range:NSMakeRange(0, str1.length)];
CGSize sizeName1 = CGRectIntegral([str1 boundingRectWithSize:CGSizeMake(cellWidth-8, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin context:nil]).size;
NSLog(#"%f,%f",sizeName.height,sizeName1.height);
if(sizeName.height > 100){
sizeName.height = 70;
}
return CGSizeMake(cellWidth, sizeName.height + sizeName1.height + 110);
}
else{
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
float cellWidth = screenWidth;
CGSize size = CGSizeMake(cellWidth, 182);
return size;
}
Thank you for your suggestions friends.
Really it's better to use tableview for this but unfortunately after using collection view for a previous design the requirement changed like this. So, I struggled.

Why is this text changing characters in Yosemite?

I'm trying to update an app for Yosemite, and one weird problem I'm getting is that the text labels on a custom control are changing characters - not distorting, but changing from "ON" to "KJ" and "OFF" to "KBB". The documents are all encoded as UTF-8 files. If anyone has any ideas, I'd love to hear them.
The code in question:
AKDrawStringAlignedInFrame(#"OFF", [NSFont boldSystemFontOfSize:0], NSCenterTextAlignment, NSIntegralRect(textRects[0]));
which calls:
void AKDrawStringAlignedInFrame(NSString *text, NSFont *font, NSTextAlignment alignment, NSRect frame) {
NSCParameterAssert(font != nil);
NSBezierPath *textPath = [NSBezierPath bezierPathWithString:text inFont:font];
NSRect textPathBounds = NSMakeRect(NSMinX([textPath bounds]), [font descender], NSWidth([textPath bounds]), [font ascender] - [font descender]);
NSAffineTransform *scale = [NSAffineTransform transform];
CGFloat xScale = NSWidth(frame)/NSWidth(textPathBounds);
CGFloat yScale = NSHeight(frame)/NSHeight(textPathBounds);
[scale scaleBy:MIN(xScale, yScale)];
[textPath transformUsingAffineTransform:scale];
textPathBounds.origin = [scale transformPoint:textPathBounds.origin];
textPathBounds.size = [scale transformSize:textPathBounds.size];
NSAffineTransform *originCorrection = [NSAffineTransform transform];
NSPoint centeredOrigin = NSRectFromCGRect(AFRectCenteredSize(NSRectToCGRect(frame), NSSizeToCGSize(textPathBounds.size))).origin;
[originCorrection translateXBy:(centeredOrigin.x - NSMinX(textPathBounds)) yBy:(centeredOrigin.y - NSMinY(textPathBounds))];
[textPath transformUsingAffineTransform:originCorrection];
if (alignment != NSJustifiedTextAlignment && alignment != NSCenterTextAlignment) {
NSAffineTransform *alignmentTransform = [NSAffineTransform transform];
CGFloat deltaX = 0;
if (alignment == NSLeftTextAlignment) deltaX = -(NSMinX([textPath bounds]) - NSMinX(frame));
else if (alignment == NSRightTextAlignment) deltaX = (NSMaxX(frame) - NSMaxX([textPath bounds]));
[alignmentTransform translateXBy:deltaX yBy:0];
[textPath transformUsingAffineTransform:alignmentTransform];
}
[textPath fill];
}
and +[NSBezierPath bezierPathWithString:inFont:] is just
+ (NSBezierPath *)bezierPathWithString:(NSString *)text inFont:(NSFont *)font {
NSBezierPath *textPath = [self bezierPath];
[textPath appendBezierPathWithString:text inFont:font];
return textPath;
}
Lastly, -[appendBezierPathWithString:text] is:
- (void)appendBezierPathWithString:(NSString *)text inFont:(NSFont *)font {
if ([self isEmpty]) [self moveToPoint:NSZeroPoint];
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:text];
CTLineRef line = CTLineCreateWithAttributedString((CFAttributedStringRef)attributedString);
CFArrayRef glyphRuns = CTLineGetGlyphRuns(line);
CFIndex count = CFArrayGetCount(glyphRuns);
for (CFIndex index = 0; index < count; index++) {
CTRunRef currentRun = (CTRunRef)CFArrayGetValueAtIndex(glyphRuns, index);
CFIndex glyphCount = CTRunGetGlyphCount(currentRun);
CGGlyph glyphs[glyphCount];
CTRunGetGlyphs(currentRun, CTRunGetStringRange(currentRun), glyphs);
NSGlyph bezierPathGlyphs[glyphCount];
for (CFIndex glyphIndex = 0; glyphIndex < glyphCount; glyphIndex++)
bezierPathGlyphs[glyphIndex] = glyphs[glyphIndex];
[self appendBezierPathWithGlyphs:bezierPathGlyphs count:glyphCount inFont:font];
}
CFRelease(line);
}
Glyph indices are specific to a font. The appendBezierPathWithString:inFont: method gets the glyph indices from Core Text (CTLine and CTRun) but it's not providing the font. Presumably, Core Text is using a default font. Later, it's using those glyph indices but it's passing the desired font, not the font that Core Text used. So, the glyph indices don't mean the same thing.
I think the solution is to construct the attributed string in that method with a font attribute:
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:text attributes:#{ NSFontAttributeName: font }];
(Normally, you have to be careful about using attributes that Core Text will understand, but I believe that NSFontAttributeName maps to kCTFontAttributeName and NSFont is toll-free bridged to CTFont.)

Blue Highlight around Custom NSButton

I want to make a custom NSButton with a solid color for its background but there is this blue highlight around the button that I can't figure out how to get rid of. Does anyone know how to get rid of it?
Thanks!
EDIT:
Here's the code for the button:
#implementation ZDButton
- (id)init {
if (self = [super init]) {
self.title = #"";
self.isSelected = false;
[self setBordered:NO];
[self setBackgroundColor:[NSColor whiteColor]];
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
[[NSColor colorWithCalibratedRed:arc4random_uniform(100) / 100.0
green:arc4random_uniform(100) / 100.0
blue:arc4random_uniform(100) / 100.0
alpha:1.0] set];
NSRectFill(dirtyRect);
NSDictionary *att = nil;
NSMutableParagraphStyle *style =
[[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[style setLineBreakMode:NSLineBreakByWordWrapping];
[style setAlignment:NSLeftTextAlignment];
att = [[NSDictionary alloc] initWithObjectsAndKeys:
style, NSParagraphStyleAttributeName,
[NSColor whiteColor],
NSForegroundColorAttributeName, nil];
int width = [self.title sizeWithAttributes:att].width;
int height = [self.title sizeWithAttributes:att].height;
int x = (dirtyRect.size.width - width) / 2;
int y = (dirtyRect.size.height - height) / 2;
NSRect centeredText = NSRectFromCGRect(CGRectMake(x, y, width, height));
[self.title drawInRect:centeredText withAttributes:att];
}
#end

Resizeable Custom NSPanel

OK, here's my situation :
I'm trying a HUD-like custom-controls collection, SNRHUDKit.
I'm specifically using SNRHUDWindow as my main window class
No matter what, although it actually works, I can't get the NSWindow (or NSPanel - doesn't make much difference) to resize, when the user drags its lower-right corner.
The code for SNRHUDWindow is :
//
// SNRHUDWindow.m
// SNRHUDKit
//
// Created by Indragie Karunaratne on 12-01-22.
// Copyright (c) 2012 indragie.com. All rights reserved.
//
#import "SNRHUDWindow.h"
#import "NSBezierPath+MCAdditions.h"
#define SNRWindowTitlebarHeight 22.f
#define SNRWindowBorderColor [NSColor blackColor]
#define SNRWindowTopColor [NSColor colorWithDeviceWhite:0.240 alpha:0.960]
#define SNRWindowBottomColor [NSColor colorWithDeviceWhite:0.150 alpha:0.960]
#define SNRWindowHighlightColor [NSColor colorWithDeviceWhite:1.000 alpha:0.200]
#define SNRWindowCornerRadius 5.f
#define SNRWindowTitleFont [NSFont systemFontOfSize:11.f]
#define SNRWindowTitleColor [NSColor colorWithDeviceWhite:0.700 alpha:1.000]
#define SNRWindowTitleShadowOffset NSMakeSize(0.f, 1.f)
#define SNRWindowTitleShadowBlurRadius 1.f
#define SNRWindowTitleShadowColor [NSColor blackColor]
#define SNRWindowButtonSize NSMakeSize(18.f, 18.f)
#define SNRWindowButtonEdgeMargin 5.f
#define SNRWindowButtonBorderColor [NSColor colorWithDeviceWhite:0.040 alpha:1.000]
#define SNRWindowButtonGradientBottomColor [NSColor colorWithDeviceWhite:0.070 alpha:1.000]
#define SNRWindowButtonGradientTopColor [NSColor colorWithDeviceWhite:0.220 alpha:1.000]
#define SNRWindowButtonDropShadowColor [NSColor colorWithDeviceWhite:1.000 alpha:0.100]
#define SNRWindowButtonCrossColor [NSColor colorWithDeviceWhite:0.450 alpha:1.000]
#define SNRWindowButtonCrossInset 1.f
#define SNRWindowButtonHighlightOverlayColor [NSColor colorWithDeviceWhite:0.000 alpha:0.300]
#define SNRWindowButtonInnerShadowColor [NSColor colorWithDeviceWhite:1.000 alpha:0.100]
#define SNRWindowButtonInnerShadowOffset NSMakeSize(0.f, 0.f)
#define SNRWindowButtonInnerShadowBlurRadius 1.f
#interface SNRHUDWindowButtonCell : NSButtonCell
#end
#interface SNRHUDWindowFrameView : NSView
- (void)snr_drawTitleInRect:(NSRect)rect;
#end
#implementation SNRHUDWindow {
NSView *__customContentView;
}
- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation
{
if ((self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:bufferingType defer:deferCreation])) {
[self setOpaque:NO];
[self setBackgroundColor:[NSColor clearColor]];
[self setMovableByWindowBackground:YES];
[self setLevel:NSFloatingWindowLevel];
}
return self;
}
- (NSRect)contentRectForFrameRect:(NSRect)windowFrame
{
windowFrame.origin = NSZeroPoint;
windowFrame.size.height -= SNRWindowTitlebarHeight;
return windowFrame;
}
+ (NSRect)frameRectForContentRect:(NSRect)windowContentRect
styleMask:(NSUInteger)windowStyle
{
windowContentRect.size.height += SNRWindowTitlebarHeight;
return windowContentRect;
}
- (NSRect)frameRectForContentRect:(NSRect)windowContent
{
windowContent.size.height += SNRWindowTitlebarHeight;
return windowContent;
}
- (void)setContentView:(NSView *)aView
{
if ([__customContentView isEqualTo:aView]) {
return;
}
NSRect bounds = [self frame];
bounds.origin = NSZeroPoint;
SNRHUDWindowFrameView *frameView = [super contentView];
if (!frameView) {
frameView = [[SNRHUDWindowFrameView alloc] initWithFrame:bounds];
NSSize buttonSize = SNRWindowButtonSize;
NSRect buttonRect = NSMakeRect(SNRWindowButtonEdgeMargin, NSMaxY(frameView.bounds) -(SNRWindowButtonEdgeMargin + buttonSize.height), buttonSize.width, buttonSize.height);
NSButton *closeButton = [[NSButton alloc] initWithFrame:buttonRect];
[closeButton setCell:[[SNRHUDWindowButtonCell alloc] init]];
[closeButton setButtonType:NSMomentaryChangeButton];
[closeButton setTarget:self];
[closeButton setAction:#selector(close)];
[closeButton setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
[frameView addSubview:closeButton];
[super setContentView:frameView];
}
if (__customContentView) {
[__customContentView removeFromSuperview];
}
__customContentView = aView;
[__customContentView setFrame:[self contentRectForFrameRect:bounds]];
[__customContentView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[frameView addSubview:__customContentView];
}
- (NSView *)contentView
{
return __customContentView;
}
- (void)setTitle:(NSString *)aString
{
[super setTitle:aString];
[[super contentView] setNeedsDisplay:YES];
}
- (BOOL)canBecomeKeyWindow
{
return YES;
}
#end
#implementation SNRHUDWindowFrameView
- (void)drawRect:(NSRect)dirtyRect
{
NSRect drawingRect = NSInsetRect(self.bounds, 0.5f, 0.5f);
NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:drawingRect xRadius:SNRWindowCornerRadius yRadius:SNRWindowCornerRadius];
[NSGraphicsContext saveGraphicsState];
[path addClip];
// Fill in the title bar with a gradient background
NSRect titleBarRect = NSMakeRect(0.f, NSMaxY(self.bounds) - SNRWindowTitlebarHeight, self.bounds.size.width, SNRWindowTitlebarHeight);
NSGradient *titlebarGradient = [[NSGradient alloc] initWithStartingColor:SNRWindowBottomColor endingColor:SNRWindowTopColor];
[titlebarGradient drawInRect:titleBarRect angle:90.f];
// Draw the window title
[self snr_drawTitleInRect:titleBarRect];
// Rest of the window has a solid fill
NSRect bottomRect = NSMakeRect(0.f, 0.f, self.bounds.size.width, self.bounds.size.height - SNRWindowTitlebarHeight);
[SNRWindowBottomColor set];
[NSBezierPath fillRect:bottomRect];
// Draw the highlight line around the top edge of the window
// Outset the width of the rectangle by 0.5px so that the highlight "bleeds" around the rounded corners
// Outset the height by 1px so that the line is drawn right below the border
NSRect highlightRect = NSInsetRect(drawingRect, 0.f, 0.5f);
// Make the height of the highlight rect something bigger than the bounds so that it won't show up on the bottom
highlightRect.size.height += 50.f;
highlightRect.origin.y -= 50.f;
NSBezierPath *highlightPath = [NSBezierPath bezierPathWithRoundedRect:highlightRect xRadius:SNRWindowCornerRadius yRadius:SNRWindowCornerRadius];
[SNRWindowHighlightColor set];
[highlightPath stroke];
[NSGraphicsContext restoreGraphicsState];
[SNRWindowBorderColor set];
[path stroke];
}
- (void)snr_drawTitleInRect:(NSRect)titleBarRect
{
NSString *title = [[self window] title];
if (!title) { return; }
NSShadow *shadow = [NSShadow new];
[shadow setShadowColor:SNRWindowTitleShadowColor];
[shadow setShadowOffset:SNRWindowTitleShadowOffset];
[shadow setShadowBlurRadius:SNRWindowTitleShadowBlurRadius];
NSMutableParagraphStyle *style = [NSMutableParagraphStyle new];
[style setAlignment:NSCenterTextAlignment];
NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:SNRWindowTitleColor, NSForegroundColorAttributeName, SNRWindowTitleFont, NSFontAttributeName, shadow, NSShadowAttributeName, style, NSParagraphStyleAttributeName, nil];
NSAttributedString *attrTitle = [[NSAttributedString alloc] initWithString:title attributes:attributes];
NSSize titleSize = attrTitle.size;
NSRect titleRect = NSMakeRect(0.f, NSMidY(titleBarRect) - (titleSize.height / 2.f), titleBarRect.size.width, titleSize.height);
[attrTitle drawInRect:NSIntegralRect(titleRect)];
}
#end
#implementation SNRHUDWindowButtonCell
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
NSRect drawingRect = NSInsetRect(cellFrame, 1.5f, 1.5f);
drawingRect.origin.y = 0.5f;
NSRect dropShadowRect = drawingRect;
dropShadowRect.origin.y += 1.f;
// Draw the drop shadow so that the bottom edge peeks through
NSBezierPath *dropShadow = [NSBezierPath bezierPathWithOvalInRect:dropShadowRect];
[SNRWindowButtonDropShadowColor set];
[dropShadow stroke];
// Draw the main circle w/ gradient & border on top of it
NSBezierPath *circle = [NSBezierPath bezierPathWithOvalInRect:drawingRect];
NSGradient *gradient = [[NSGradient alloc] initWithStartingColor:SNRWindowButtonGradientBottomColor endingColor:SNRWindowButtonGradientTopColor];
[gradient drawInBezierPath:circle angle:270.f];
[SNRWindowButtonBorderColor set];
[circle stroke];
// Draw the cross
NSBezierPath *cross = [NSBezierPath bezierPath];
CGFloat boxDimension = floor(drawingRect.size.width * cos(45.f)) - SNRWindowButtonCrossInset;
CGFloat origin = round((drawingRect.size.width - boxDimension) / 2.f);
NSRect boxRect = NSMakeRect(1.f + origin, origin, boxDimension, boxDimension);
NSPoint bottomLeft = NSMakePoint(boxRect.origin.x, NSMaxY(boxRect));
NSPoint topRight = NSMakePoint(NSMaxX(boxRect), boxRect.origin.y);
NSPoint bottomRight = NSMakePoint(topRight.x, bottomLeft.y);
NSPoint topLeft = NSMakePoint(bottomLeft.x, topRight.y);
[cross moveToPoint:bottomLeft];
[cross lineToPoint:topRight];
[cross moveToPoint:bottomRight];
[cross lineToPoint:topLeft];
[SNRWindowButtonCrossColor set];
[cross setLineWidth:2.f];
[cross stroke];
// Draw the inner shadow
NSShadow *shadow = [[NSShadow alloc] init];
[shadow setShadowColor:SNRWindowButtonInnerShadowColor];
[shadow setShadowBlurRadius:SNRWindowButtonInnerShadowBlurRadius];
[shadow setShadowOffset:SNRWindowButtonInnerShadowOffset];
NSRect shadowRect = drawingRect;
shadowRect.size.height = origin;
[NSGraphicsContext saveGraphicsState];
[NSBezierPath clipRect:shadowRect];
[circle fillWithInnerShadow:shadow];
[NSGraphicsContext restoreGraphicsState];
if ([self isHighlighted]) {
[SNRWindowButtonHighlightOverlayColor set];
[circle fill];
}
}
#end
Any ideas what could be responsible for the NSPanel losing its resizing ability?
I'm using this framework as well, and the reason that resizing doesn't work by default is this line in the initWithContentRect method:
if ((self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:bufferingType defer:deferCreation])) {
As you can see, instead of passing the windowStyle bitmask provided to super's init method, it passes through just NSBorderlessWindowMask. A bit of sniffing around shows that for resizing to be possible at all, the styleMask must have NSResizableWindowMask included in the bitmask.
So, changing the line to
if ((self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask|NSResizableWindowMask backing:bufferingType defer:deferCreation])) {
should solve your problem.

drawWithFrame NSOutlineView Flickr

I have a custom cell class for NSOutlineView
In the cell class I have implemented the drawWithFrame.
The rect provided(cellFrame) I divide into 3 parts
(a) Image
(b) Text
(c) Darwing (ellipse/circle / rectangle)
The image is drawn using [image compositeToPoint:imageFrame.origin operation:NSCompositeSourceOver];
The ellipse is drawn using [[NSBezierPath bezierPathWithRoundedRect:ellipseRect xRadius:10 yRadius:10] fill];
The text rect is given to the super class to draw the text
[super drawInteriorWithFrame:newFrame inView:controlView];
Now my problem is that when any cell of the outline view expands, all the drawing (ellipse etc) flickr and appear to be redrawn, even if the cell was not expanded.
Can anyone help me to resolve this..
Here is the code
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView
{
//cellFrame.size.height -=16;
Option *ol = [self representedObject];
uint64_t sz;
int fontSize=10;
NSString *sizeText;
MyFile *tmpf;
//NSImage *image = [ol getImage];
if (image != nil)
{
// the cell has an image: draw the normal item cell
NSSize imageSize;
NSRect imageFrame;
imageSize = [image size];
NSDivideRect(cellFrame, &imageFrame, &cellFrame, 3 + imageSize.width, NSMinXEdge);
imageFrame.origin.x += kImageOriginXOffset;
imageFrame.origin.y -= kImageOriginYOffset;
imageFrame.size = NSMakeSize(12,12);
if ([controlView isFlipped])
imageFrame.origin.y += ceil((cellFrame.size.height + imageFrame.size.height) / 2);
else
imageFrame.origin.y += ceil((cellFrame.size.height - imageFrame.size.height) / 2);
[image compositeToPoint:imageFrame.origin operation:NSCompositeSourceOver];
imageFrame.origin.y+=18;
imageFrame.size.width = cellFrame.size.width - 18;
imageFrame.origin.x+=18;
sz = [ol getsize];
/////////////////////////////////
NSRect newFrame = cellFrame;
newFrame.origin.x += kTextOriginXOffset;
newFrame.origin.y += kTextOriginYOffset;
newFrame.size.height -= kTextHeightAdjust;
newFrame.size.width -= 65;
if(sz)
{
//newFrame.origin.x += 65;
NSRect tmpframe = newFrame;
NSRect ellipseRect = NSMakeRect(tmpframe.origin.x+tmpframe.size.width+1,
tmpframe.origin.y+ kTextOriginYOffset,
60,16);
//////// ****ALLOC ********
tmpf = [[MyFile alloc] init];
[tmpf setfsize:sz];
sizeText = [tmpf getFormattedfize];
// [NSShadow setShadowWithOffset:NSMakeSize(0, -8 * 1) blurRadius:12 * 1
// color:[NSColor colorWithCalibratedWhite:0 alpha:0.75]];
[[NSColor colorWithCalibratedWhite:0.9 alpha:1.0] set];
[[NSBezierPath bezierPathWithRoundedRect:ellipseRect xRadius:10 yRadius:10] fill];
// [NSShadow clearShadow];
TextAttributes = [NSDictionary dictionaryWithObjectsAndKeys: [NSColor textColor],
NSForegroundColorAttributeName,
[NSFont systemFontOfSize:10],
NSFontAttributeName, nil];
[sizeText drawAtPoint:NSMakePoint(ellipseRect.origin.x+3, ellipseRect.origin.y+2)
withAttributes:TextAttributes];
//////// ****RELEASE *******
[tmpf release];
}
[super drawInteriorWithFrame:newFrame inView:controlView];
}
}