Skip to content

Instantly share code, notes, and snippets.

@rickfillion
Created March 24, 2021 14:10
Show Gist options
  • Save rickfillion/10d4d2ea2829880c2235f0e93c6e4088 to your computer and use it in GitHub Desktop.
Save rickfillion/10d4d2ea2829880c2235f0e93c6e4088 to your computer and use it in GitHub Desktop.
Bodega Awning Window
//
// AwningWindow.m
// Bodega
//
// Created by Rick Fillion on 14/04/09.
// Copyright 2009 Centrix.ca. All rights reserved.
//
#import "AwningWindow.h"
#import "NSNotificationCenter+Bodega.h"
#include <tgmath.h>
@interface AwningWindow (Private)
- (NSEvent *)convertMouseEventToParentWindowEvent:(NSEvent *)event;
@end
@implementation AwningWindow
- (id) initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation
{
self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:FALSE];
if (!self) { return nil; }
awningLeft = [[NSImage imageNamed:@"AwningLeft"] retain];
awningRight = [[NSImage imageNamed:@"AwningRight"] retain];
awningSlice = [[NSImage imageNamed:@"AwningSlice"] retain];
[self setBackgroundColor: [self sizedBackground]];
return self;
}
- (void)dealloc
{
[awningLeft release];
[awningRight release];
[awningSlice release];
[super dealloc];
}
- (NSColor *)sizedBackground
{
NSSize windowSize = [self frame].size;
NSSize adjustedWindowSize = windowSize;
adjustedWindowSize.width += 100.0; // we add a bunch of whitespace here so that in Snow Leopard it doesn't show the wrap-around.
NSImage *awningCompositeImage = [[[NSImage alloc] initWithSize:adjustedWindowSize] autorelease];
CGFloat sideSlices = 16;
CGFloat leftRightWidth = [awningLeft size].width + [awningRight size].width;
CGFloat remainingWidth = roundf(windowSize.width - leftRightWidth);
NSInteger sliceCount = ((NSInteger)remainingWidth) / ((NSInteger)[awningSlice size].width);
remainingWidth -= roundf(sliceCount * [awningSlice size].width);
CGFloat leftWidth = roundf([awningLeft size].width + (sideSlices / (sideSlices*2 + sliceCount)) * remainingWidth);
CGFloat rightWidth = roundf([awningRight size].width + (sideSlices / (sideSlices*2 + sliceCount)) * remainingWidth);
NSImage *slicesImage = nil;
if (sliceCount * [awningSlice size].width > 0)
{
slicesImage = [[[NSImage alloc] initWithSize:NSMakeSize(sliceCount * [awningSlice size].width, [awningSlice size].height)] autorelease];
NSRect sliceRect = NSMakeRect(0, 0, [awningSlice size].width, [awningSlice size].height);
[slicesImage lockFocus];
for (NSInteger count = 0; count < sliceCount; count++)
{
[awningSlice drawInRect:sliceRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
sliceRect.origin.x += round(sliceRect.size.width);
}
[slicesImage unlockFocus];
}
[awningCompositeImage lockFocus];
{
if (leftWidth + rightWidth > windowSize.width)
{
// there's no slices, and the images are just going to overlap cause the window's too small
leftWidth = roundf(windowSize.width/2);
rightWidth = roundf(windowSize.width - leftWidth);
}
if (!slicesImage && (leftWidth + rightWidth < windowSize.width))
{
// no slices, and the images don't quite take up enough room. make the left one bigger
leftWidth = roundf(windowSize.width - rightWidth);
}
NSRect leftRect = NSMakeRect(0, 0, leftWidth, [awningLeft size].height);
[awningLeft drawInRect:leftRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
NSRect slicesRect = NSMakeRect(leftWidth, 0, windowSize.width - leftWidth - rightWidth,[awningSlice size].height);
[slicesImage drawInRect:slicesRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
NSRect rightRect = NSMakeRect(windowSize.width-rightWidth, 0, rightWidth, [awningRight size].height);
[awningRight drawInRect:rightRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
}
[awningCompositeImage unlockFocus];
return [NSColor colorWithPatternImage:awningCompositeImage];
}
- (void)setFrame:(NSRect)windowFrame display:(BOOL)displayViews
{
[self setBackgroundColor:[self sizedBackground]];
[super setFrame:windowFrame display: YES];
[self setBackgroundColor:[self sizedBackground]];
}
- (void)setFrame:(NSRect)windowFrame display:(BOOL)displayViews animate:(BOOL)performAnimation
{
[super setFrame:windowFrame display:NO animate:NO];
[self setBackgroundColor:[self sizedBackground]];
}
#pragma mark NSResponder
- (void)mouseDown:(NSEvent *)theEvent
{
lastLocationInWindow = [theEvent locationInWindow];
[[NSNotificationCenter defaultCenter] postNotificaitonAwningWindowDidStartMove];
}
- (void)mouseDragged:(NSEvent*)theEvent
{
NSWindow *mainWindow = [self parentWindow];
CGFloat deltaX = lastLocationInWindow.x - [theEvent locationInWindow].x;
CGFloat deltaY = lastLocationInWindow.y - [theEvent locationInWindow].y;
NSRect frame = [mainWindow frame];
frame.origin.x -= deltaX;
frame.origin.y -= deltaY;
[mainWindow setFrameOrigin:frame.origin];
}
- (void)mouseUp:(NSEvent *)theEvent
{
[[NSNotificationCenter defaultCenter] postNotificaitonAwningWindowDidEndMove];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment