Skip to content

Instantly share code, notes, and snippets.

@nilium
Created March 6, 2011 20:20

Revisions

  1. nilium created this gist Mar 6, 2011.
    57 changes: 57 additions & 0 deletions NSImage+NinePartDrawing.h
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,57 @@

    /*
    * NSImage+NinePartDrawing.h
    *
    * Copyright (c) 2011 Noel R. Cower
    *
    * This software is provided 'as-is', without any express or implied
    * warranty. In no event will the authors be held liable for any damages
    * arising from the use of this software.
    *
    * Permission is granted to anyone to use this software for any purpose,
    * including commercial applications, and to alter it and redistribute it
    * freely, subject to the following restrictions:
    *
    * 1. The origin of this software must not be misrepresented; you must not
    * claim that you wrote the original software. If you use this software
    * in a product, an acknowledgment in the product documentation would be
    * appreciated but is not required.
    *
    * 2. Altered source versions must be plainly marked as such, and must not be
    * misrepresented as being the original software.
    *
    * 3. This notice may not be removed or altered from any source
    * distribution.
    *
    */

    #import <Cocoa/Cocoa.h>

    extern const CGFloat NNoCap;

    @interface NSImage (NinePartDrawing)

    - (void)drawInRect:(NSRect)dstSpacePortionRect
    operation:(NSCompositingOperation)op
    fraction:(CGFloat)requestedAlpha
    respectFlipped:(BOOL)respectContextIsFlipped
    hints:(NSDictionary *)hints
    topCap:(CGFloat)top
    bottomCap:(CGFloat)bottom
    leftCap:(CGFloat)left
    rightCap:(CGFloat)right;

    - (void)drawInRect:(NSRect)dstSpacePortionRect
    topCap:(CGFloat)top
    bottomCap:(CGFloat)bottom
    leftCap:(CGFloat)left
    rightCap:(CGFloat)right;

    - (void)drawInRect:(NSRect)dstSpacePortionRect
    heightCap:(CGFloat)heightCap
    widthCap:(CGFloat)widthCap;

    - (void)drawInRect:(NSRect)dstSpacePortionRect
    withCap:(CGFloat)cap;

    @end
    212 changes: 212 additions & 0 deletions NSImage+NinePartDrawing.m
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,212 @@

    /*
    * NSImage+NinePartDrawing.m
    *
    * Copyright (c) 2011 Noel R. Cower
    *
    * This software is provided 'as-is', without any express or implied
    * warranty. In no event will the authors be held liable for any damages
    * arising from the use of this software.
    *
    * Permission is granted to anyone to use this software for any purpose,
    * including commercial applications, and to alter it and redistribute it
    * freely, subject to the following restrictions:
    *
    * 1. The origin of this software must not be misrepresented; you must not
    * claim that you wrote the original software. If you use this software
    * in a product, an acknowledgment in the product documentation would be
    * appreciated but is not required.
    *
    * 2. Altered source versions must be plainly marked as such, and must not be
    * misrepresented as being the original software.
    *
    * 3. This notice may not be removed or altered from any source
    * distribution.
    *
    */

    #import "NSImage+NinePartDrawing.h"

    const CGFloat NNoCap = -1;

    @implementation NSImage (NinePartDrawing)

    - (void)drawInRect:(NSRect)dstSpacePortionRect
    topCap:(CGFloat)top
    bottomCap:(CGFloat)bottom
    leftCap:(CGFloat)left
    rightCap:(CGFloat)right {
    [self drawInRect:dstSpacePortionRect
    operation:NSCompositeSourceOver
    fraction:1.0
    respectFlipped:YES
    hints:nil
    topCap:top
    bottomCap:left
    leftCap:bottom
    rightCap:right];
    }

    - (void)drawInRect:(NSRect)dstSpacePortionRect
    heightCap:(CGFloat)heightCap
    widthCap:(CGFloat)widthCap {
    [self drawInRect:dstSpacePortionRect
    operation:NSCompositeSourceOver
    fraction:1.0
    respectFlipped:YES
    hints:nil
    topCap:heightCap
    bottomCap:heightCap
    leftCap:widthCap
    rightCap:widthCap];
    }

    - (void)drawInRect:(NSRect)dstSpacePortionRect
    withCap:(CGFloat)cap {
    [self drawInRect:dstSpacePortionRect
    operation:NSCompositeSourceOver
    fraction:1.0
    respectFlipped:YES
    hints:nil
    topCap:cap
    bottomCap:cap
    leftCap:cap
    rightCap:cap];
    }

    - (void)drawInRect:(NSRect)dstSpacePortionRect
    operation:(NSCompositingOperation)op
    fraction:(CGFloat)requestedAlpha
    respectFlipped:(BOOL)respectContextIsFlipped
    hints:(NSDictionary *)hints
    topCap:(CGFloat)top
    bottomCap:(CGFloat)bottom
    leftCap:(CGFloat)left
    rightCap:(CGFloat)right {

    top = fmax(top, 0);
    bottom = fmax(bottom, 0);
    left = fmax(left, 0);
    right = fmax(right, 0);

    NSSize size = [self size];
    NSRect srcRect = NSZeroRect;
    NSRect dstRect = dstSpacePortionRect;

    srcRect.size.width = left;
    srcRect.size.height = bottom;
    dstRect.size = srcRect.size;

    if (bottom > 0) {
    if (left > 0) {
    [self drawInRect:dstRect
    fromRect:srcRect
    operation:op
    fraction:requestedAlpha
    respectFlipped:respectContextIsFlipped
    hints:hints];
    }

    dstRect.origin.x += (srcRect.origin.x = left);
    dstRect.size.width = dstSpacePortionRect.size.width - (left + right);
    srcRect.size.width = size.width - left - right;

    [self drawInRect:dstRect
    fromRect:srcRect
    operation:op
    fraction:requestedAlpha
    respectFlipped:respectContextIsFlipped
    hints:hints];

    dstRect.origin.x = (dstSpacePortionRect.origin.x + dstSpacePortionRect.size.width) - right;
    srcRect.origin.x = size.width - right;
    dstRect.size.width = srcRect.size.width = right;

    if (right > 0) {
    [self drawInRect:dstRect
    fromRect:srcRect
    operation:op
    fraction:requestedAlpha
    respectFlipped:respectContextIsFlipped
    hints:hints];
    }
    }

    srcRect.size.height = size.height - (bottom + top);
    dstRect.size.height = dstSpacePortionRect.size.height - (bottom + top);
    dstRect.origin.y = dstSpacePortionRect.origin.y + (srcRect.origin.y = bottom);

    if (right > 0) {
    [self drawInRect:dstRect
    fromRect:srcRect
    operation:op
    fraction:requestedAlpha
    respectFlipped:respectContextIsFlipped
    hints:hints];
    }

    if (left > 0) {
    srcRect.origin.x = 0;
    dstRect.origin.x = dstSpacePortionRect.origin.x;
    dstRect.size.width = srcRect.size.width = left;

    [self drawInRect:dstRect
    fromRect:srcRect
    operation:op
    fraction:requestedAlpha
    respectFlipped:respectContextIsFlipped
    hints:hints];
    }

    dstRect.origin.x = dstSpacePortionRect.origin.x + (srcRect.origin.x = left);
    dstRect.size.width = dstSpacePortionRect.size.width - (left + right);
    srcRect.size.width = size.width - left - right;

    [self drawInRect:dstRect
    fromRect:srcRect
    operation:op
    fraction:requestedAlpha
    respectFlipped:respectContextIsFlipped
    hints:hints];

    if (top > 0) {
    srcRect.origin.y = size.height - top;
    dstRect.origin.y = (dstSpacePortionRect.origin.y + dstSpacePortionRect.size.height) - top;
    dstRect.size.height = srcRect.size.height = top;

    [self drawInRect:dstRect
    fromRect:srcRect
    operation:op
    fraction:requestedAlpha
    respectFlipped:respectContextIsFlipped
    hints:hints];

    if (right > 0) {
    srcRect.origin.x = size.width - right;
    dstRect.origin.x = (dstSpacePortionRect.origin.x + dstSpacePortionRect.size.width) - right;
    srcRect.size.width = dstRect.size.width = right;

    [self drawInRect:dstRect
    fromRect:srcRect
    operation:op
    fraction:requestedAlpha
    respectFlipped:respectContextIsFlipped
    hints:hints];
    }

    if (left > 0) {
    srcRect.origin.x = 0;
    dstRect.origin.x = dstSpacePortionRect.origin.x;
    srcRect.size.width = dstRect.size.width = left;

    [self drawInRect:dstRect
    fromRect:srcRect
    operation:op
    fraction:requestedAlpha
    respectFlipped:respectContextIsFlipped
    hints:hints];
    }
    }
    }

    @end