Chameleon Applications

Chameleon Applications Svn Source Tree

Root/branches/diebuche/ChameleonPrefPane/Sources/RoundedBox.m

1//
2// RoundedBox.m
3// RoundedBox
4//
5// Created by Matt Gemmell on 01/11/2005.
6// Copyright 2006 Matt Gemmell. http://mattgemmell.com/
7//
8// Permission to use this code:
9//
10// Feel free to use this code in your software, either as-is or
11// in a modified form. Either way, please include a credit in
12// your software's "About" box or similar, mentioning at least
13// my name (Matt Gemmell). A link to my site would be nice too.
14//
15// Permission to redistribute this code:
16//
17// You can redistribute this code, as long as you keep these
18// comments. You can also redistribute modified versions of the
19// code, as long as you add comments to say that you've made
20// modifications (keeping these original comments too).
21//
22// If you do use or redistribute this code, an email would be
23// appreciated, just to let me know that people are finding my
24// code useful. You can reach me at matt.gemmell@gmail.com
25//
26
27#import "RoundedBox.h"
28
29
30@implementation RoundedBox
31
32
33- (id)initWithFrame:(NSRect)frame {
34 self = [super initWithFrame:frame];
35 if (self) {
36 [self setDefaults];
37 }
38 return self;
39}
40
41
42- (void)dealloc
43{
44 [borderColor release];
45 [titleColor release];
46 [gradientStartColor release];
47 [gradientEndColor release];
48 [backgroundColor release];
49 [titleAttrs release];
50
51 [super dealloc];
52}
53
54
55- (void)setDefaults
56{
57 borderWidth = 2.0;
58 [self setBorderColor:[NSColor grayColor]];
59 [self setTitleColor:[NSColor whiteColor]];
60 [self setGradientStartColor:[NSColor colorWithCalibratedWhite:0.93 alpha:1.0]];
61 [self setGradientEndColor:[NSColor colorWithCalibratedWhite:0.82 alpha:1.0]];
62 [self setBackgroundColor:[NSColor colorWithCalibratedWhite:0.90 alpha:1.0]];
63 [self setTitleFont:[NSFont boldSystemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]];
64
65 // Set up text attributes for drawing
66 NSMutableParagraphStyle *paragraphStyle;
67 paragraphStyle = [[NSMutableParagraphStyle alloc] init];
68 [paragraphStyle setParagraphStyle:[NSParagraphStyle defaultParagraphStyle]];
69 [paragraphStyle setAlignment:NSLeftTextAlignment];
70 [paragraphStyle setLineBreakMode:NSLineBreakByTruncatingTail];
71
72 titleAttrs = [[NSMutableDictionary dictionaryWithObjectsAndKeys:
73 [self titleFont], NSFontAttributeName,
74 [self titleColor], NSForegroundColorAttributeName,
75 [paragraphStyle autorelease], NSParagraphStyleAttributeName,
76 nil] retain];
77
78 [self setDrawsFullTitleBar:YES];
79 [self setSelected:NO];
80 [self setDrawsGradientBackground:YES];
81}
82
83
84- (void)awakeFromNib
85{
86 // For when we've been created in a nib file
87 [self setDefaults];
88
89}
90
91
92- (BOOL)preservesContentDuringLiveResize
93{
94 // NSBox returns YES for this, but doing so would screw up the gradients.
95 return NO;
96}
97
98
99- (void)drawRect:(NSRect)rect {
100
101 // Construct rounded rect path
102 NSRect boxRect = [self bounds];
103 NSRect bgRect = boxRect;
104 bgRect = NSInsetRect(boxRect, borderWidth / 2.0, borderWidth / 2.0);
105 bgRect = NSIntegralRect(bgRect);
106 bgRect.origin.x += 0.5;
107 bgRect.origin.y += 0.5;
108 int minX = NSMinX(bgRect);
109 int midX = NSMidX(bgRect);
110 int maxX = NSMaxX(bgRect);
111 int minY = NSMinY(bgRect);
112 int midY = NSMidY(bgRect);
113 int maxY = NSMaxY(bgRect);
114 float radius = 4.0;
115 NSBezierPath *bgPath = [NSBezierPath bezierPath];
116
117 // Bottom edge and bottom-right curve
118 [bgPath moveToPoint:NSMakePoint(midX, minY)];
119 [bgPath appendBezierPathWithArcFromPoint:NSMakePoint(maxX, minY)
120 toPoint:NSMakePoint(maxX, midY)
121 radius:radius];
122
123 // Right edge and top-right curve
124 [bgPath appendBezierPathWithArcFromPoint:NSMakePoint(maxX, maxY)
125 toPoint:NSMakePoint(midX, maxY)
126 radius:radius];
127
128 // Top edge and top-left curve
129 [bgPath appendBezierPathWithArcFromPoint:NSMakePoint(minX, maxY)
130 toPoint:NSMakePoint(minX, midY)
131 radius:radius];
132
133 // Left edge and bottom-left curve
134 [bgPath appendBezierPathWithArcFromPoint:NSMakePoint(minX, minY)
135 toPoint:NSMakePoint(midX, minY)
136 radius:radius];
137 [bgPath closePath];
138
139
140 // Draw background
141
142 if ([self drawsGradientBackground]) {
143 // Draw gradient background
144 NSGraphicsContext *nsContext = [NSGraphicsContext currentContext];
145 [nsContext saveGraphicsState];
146 [bgPath addClip];
147 NSGradient *gradient = [[[NSGradient alloc]
148 initWithStartingColor:[self gradientStartColor]
149 endingColor:[self gradientEndColor]] autorelease];
150 NSRect gradientRect = [bgPath bounds];
151 [gradient drawInRect:gradientRect angle:270.0];
152 [nsContext restoreGraphicsState];
153 } else {
154 // Draw solid color background
155 [backgroundColor set];
156 [bgPath fill];
157 }
158
159
160 // Create drawing rectangle for title
161
162 float titleHInset = borderWidth + 4.0;
163 float titleVInset = borderWidth;
164 NSSize titleSize = [[self title] sizeWithAttributes:titleAttrs];
165 NSRect titleRect = NSMakeRect(boxRect.origin.x + titleHInset,
166 boxRect.origin.y + boxRect.size.height - titleSize.height - (titleVInset * 2.0),
167 titleSize.width + borderWidth,
168 titleSize.height);
169 titleRect.size.width = MIN(titleRect.size.width, boxRect.size.width - (2.0 * titleHInset));
170
171 if ([self selected]) {
172 [[NSColor alternateSelectedControlColor] set];
173 // We use the alternate (darker) selectedControlColor since the regular one is too light.
174 // The alternate one is the highlight color for NSTableView, NSOutlineView, etc.
175 // This mimics how Automator highlights the selected action in a workflow.
176 } else {
177 [borderColor set];
178 }
179
180
181 // Draw title background
182 //NSRectFill(titleRect);
183 [[self titlePathWithinRect:bgRect cornerRadius:radius titleRect:titleRect] fill];
184
185
186 // Draw rounded rect around entire box
187 if (borderWidth > 0.0) {
188 [bgPath setLineWidth:borderWidth];
189 [bgPath stroke];
190 }
191
192
193 // Draw title text
194 [[self title] drawInRect:titleRect withAttributes:titleAttrs];
195 //[[self titleCell] setTextColor:[self titleColor]];
196 //[[self titleCell] drawWithFrame:titleRect inView:self];
197}
198
199
200- (NSBezierPath *)titlePathWithinRect:(NSRect)rect cornerRadius:(float)radius titleRect:(NSRect)titleRect
201{
202 // Construct rounded rect path
203
204 NSRect bgRect = rect;
205 int minX = NSMinX(bgRect);
206 int maxX = minX + titleRect.size.width + ((titleRect.origin.x - rect.origin.x) * 2.0);
207 int maxY = NSMaxY(bgRect);
208 int minY = NSMinY(titleRect) - (maxY - (titleRect.origin.y + titleRect.size.height));
209 float titleExpansionThreshold = 20.0;
210 // i.e. if there's less than 20px space to the right of the short titlebar, just draw the full one.
211
212 NSBezierPath *path = [NSBezierPath bezierPath];
213
214 [path moveToPoint:NSMakePoint(minX, minY)];
215
216 if (bgRect.size.width - titleRect.size.width >= titleExpansionThreshold && ![self drawsFullTitleBar]) {
217 // Draw a short titlebar
218 [path appendBezierPathWithArcFromPoint:NSMakePoint(maxX, minY)
219 toPoint:NSMakePoint(maxX, maxY)
220 radius:radius];
221 [path lineToPoint:NSMakePoint(maxX, maxY)];
222 } else {
223 // Draw full titlebar, since we're either set to always do so, or we don't have room for a short one.
224 [path lineToPoint:NSMakePoint(NSMaxX(bgRect), minY)];
225 [path appendBezierPathWithArcFromPoint:NSMakePoint(NSMaxX(bgRect), maxY)
226 toPoint:NSMakePoint(NSMaxX(bgRect) - (bgRect.size.width / 2.0), maxY)
227 radius:radius];
228 }
229
230 [path appendBezierPathWithArcFromPoint:NSMakePoint(minX, maxY)
231 toPoint:NSMakePoint(minX, minY)
232 radius:radius];
233
234 [path closePath];
235
236 return path;
237}
238
239
240- (void)setTitle:(NSString *)newTitle
241{
242 [super setTitle:newTitle];
243 [self setNeedsDisplay:YES];
244}
245
246
247- (BOOL)drawsFullTitleBar
248{
249 return drawsFullTitleBar;
250}
251
252
253- (void)setDrawsFullTitleBar:(BOOL)newDrawsFullTitleBar
254{
255 drawsFullTitleBar = newDrawsFullTitleBar;
256 [self setNeedsDisplay:YES];
257}
258
259
260- (BOOL)selected
261{
262 return selected;
263}
264
265
266- (void)setSelected:(BOOL)newSelected
267{
268 selected = newSelected;
269 [self setNeedsDisplay:YES];
270}
271
272
273- (NSColor *)borderColor
274{
275 return borderColor;
276}
277
278
279- (void)setBorderColor:(NSColor *)newBorderColor
280{
281 [newBorderColor retain];
282 [borderColor release];
283 borderColor = newBorderColor;
284 [self setNeedsDisplay:YES];
285}
286
287- (void)setBorderWidth:(CGFloat)newBorderWidth
288{
289borderWidth = newBorderWidth;
290 [self setNeedsDisplay:YES];
291}
292
293- (NSColor *)titleColor
294{
295 return titleColor;
296}
297
298
299- (void)setTitleColor:(NSColor *)newTitleColor
300{
301 [newTitleColor retain];
302 [titleColor release];
303 titleColor = newTitleColor;
304
305 [titleAttrs setObject:titleColor forKey:NSForegroundColorAttributeName];
306
307 [self setNeedsDisplay:YES];
308}
309
310
311- (NSColor *)gradientStartColor
312{
313 return gradientStartColor;
314}
315
316
317- (void)setGradientStartColor:(NSColor *)newGradientStartColor
318{
319 // Must ensure gradient colors are in NSCalibratedRGBColorSpace, or Core Image gets angry.
320 NSColor *newCalibratedGradientStartColor = [newGradientStartColor colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
321 [newCalibratedGradientStartColor retain];
322 [gradientStartColor release];
323 gradientStartColor = newCalibratedGradientStartColor;
324 if ([self drawsGradientBackground]) {
325 [self setNeedsDisplay:YES];
326 }
327}
328
329
330- (NSColor *)gradientEndColor
331{
332 return gradientEndColor;
333}
334
335
336- (void)setGradientEndColor:(NSColor *)newGradientEndColor
337{
338 // Must ensure gradient colors are in NSCalibratedRGBColorSpace, or Core Image gets angry.
339 NSColor *newCalibratedGradientEndColor = [newGradientEndColor colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
340 [newCalibratedGradientEndColor retain];
341 [gradientEndColor release];
342 gradientEndColor = newCalibratedGradientEndColor;
343 if ([self drawsGradientBackground]) {
344 [self setNeedsDisplay:YES];
345 }
346}
347
348
349- (NSColor *)backgroundColor
350{
351 return backgroundColor;
352}
353
354
355- (void)setBackgroundColor:(NSColor *)newBackgroundColor
356{
357 [newBackgroundColor retain];
358 [backgroundColor release];
359 backgroundColor = newBackgroundColor;
360 if (![self drawsGradientBackground]) {
361 [self setNeedsDisplay:YES];
362 }
363}
364
365
366- (BOOL)drawsGradientBackground
367{
368 return drawsGradientBackground;
369}
370
371
372- (void)setDrawsGradientBackground:(BOOL)newDrawsGradientBackground
373{
374 drawsGradientBackground = newDrawsGradientBackground;
375 [self setNeedsDisplay:YES];
376}
377
378
379@end
380

Archive Download this file

Revision: 85