1 /* Copyright (c) 2006-2007 Christopher J. W. Lloyd <cjwl@objc.net>
3 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
9 #import <AppKit/NSGraphics.h>
10 #import <AppKit/NSGraphicsContextFunctions.h>
11 #import <AppKit/NSColor.h>
12 #import <AppKit/NSView.h>
13 #import <AppKit/NSRaise.h>
15 #import <AppKit/NSDisplay.h>
16 #import <ApplicationServices/ApplicationServices.h>
18 #import "NSPoofAnimation.h"
20 const float NSBlack=0;
21 const float NSDarkGray=0.333;
22 const float NSLightGray=0.667;
23 const float NSWhite=1.0;
25 NSString * const NSDeviceBlackColorSpace=@"NSDeviceBlackColorSpace";
26 NSString * const NSDeviceWhiteColorSpace=@"NSDeviceWhiteColorSpace";
27 NSString * const NSDeviceRGBColorSpace=@"NSDeviceRGBColorSpace";
28 NSString * const NSDeviceCMYKColorSpace=@"NSDeviceCMYKColorSpace";
29 NSString * const NSCalibratedBlackColorSpace=@"NSCalibratedBlackColorSpace";
30 NSString * const NSCalibratedWhiteColorSpace=@"NSCalibratedWhiteColorSpace";
31 NSString * const NSCalibratedRGBColorSpace=@"NSCalibratedRGBColorSpace";
32 NSString * const NSNamedColorSpace=@"NSNamedColorSpace";
33 NSString * const NSPatternColorSpace=@"NSPatternColorSpace";
35 NSString * const NSDeviceIsScreen=@"NSDeviceIsScreen";
36 NSString * const NSDeviceIsPrinter=@"NSDeviceIsPrinter";
37 NSString * const NSDeviceSize=@"NSDeviceSize";
38 NSString * const NSDeviceResolution=@"NSDeviceResolution";
39 NSString * const NSDeviceColorSpaceName=@"NSDeviceColorSpaceName";
40 NSString * const NSDeviceBitsPerSample=@"NSDeviceBitsPerSample";
42 static inline CGBlendMode blendModeForCompositeOp(NSCompositingOperation op){
43 static CGBlendMode table[]={
48 kCGBlendModeSourceOut,
49 kCGBlendModeSourceAtop,
50 kCGBlendModeDestinationOver,
51 kCGBlendModeDestinationIn,
52 kCGBlendModeDestinationOut,
53 kCGBlendModeDestinationAtop,
55 kCGBlendModePlusDarker,
56 kCGBlendModeNormal, // FIXME: highlight
57 kCGBlendModePlusLighter,
60 if(op<NSCompositeClear || op>NSCompositePlusLighter)
61 return NSCompositeCopy;
66 void NSRectClipList(const NSRect *rects, int count) {
67 CGContextRef graphicsPort=NSCurrentGraphicsPort();
69 CGContextClipToRects(graphicsPort,rects,count);
72 void NSRectClip(NSRect rect) {
73 CGContextRef graphicsPort=NSCurrentGraphicsPort();
75 CGContextClipToRect(graphicsPort,rect);
79 void NSRectFillListWithColors(const NSRect *rects,NSColor **colors,int count) {
80 CGContextRef context=NSCurrentGraphicsPort();
83 CGContextSaveGState(context);
84 CGContextSetBlendMode(context,kCGBlendModeCopy);
87 // FIXME: the groove/button rect generating code can generate negative size rects which draw incorrectly
88 // this either needs to be fixed in the drawing or the rect generation
89 if(rects[i].size.width>0 && rects[i].size.height>0)
92 CGContextRestoreGState(context);
95 void NSRectFillListWithGrays(const NSRect *rects,const float *grays,int count) {
96 CGContextRef context=NSCurrentGraphicsPort();
99 CGContextSaveGState(context);
100 CGContextSetBlendMode(context,kCGBlendModeCopy);
101 for(i=0;i<count;i++){
102 CGContextSetGrayFillColor(context,grays[i],1.0);
103 // FIXME: the groove/button rect generating code can generate negative size rects which draw incorrectly
104 // this either needs to be fixed in the drawing or the rect generation
105 if(rects[i].size.width>0 && rects[i].size.height>0)
106 CGContextFillRect(context,rects[i]);
108 CGContextRestoreGState(context);
111 void NSRectFillList(const NSRect *rects, int count) {
112 CGContextRef context=NSCurrentGraphicsPort();
113 CGContextSaveGState(context);
114 CGContextSetBlendMode(context,kCGBlendModeCopy);
115 CGContextFillRects(NSCurrentGraphicsPort(),rects,count);
116 CGContextRestoreGState(context);
119 void NSRectFill(NSRect rect) {
120 CGContextRef context=NSCurrentGraphicsPort();
121 CGContextSaveGState(context);
122 CGContextSetBlendMode(context,kCGBlendModeCopy);
123 CGContextFillRect(NSCurrentGraphicsPort(),rect);
124 CGContextRestoreGState(context);
127 void NSEraseRect(NSRect rect) {
128 CGContextRef context=NSCurrentGraphicsPort();
129 CGContextSaveGState(context);
130 [[NSColor whiteColor] setFill];
131 CGContextSetBlendMode(context,kCGBlendModeCopy);
132 CGContextFillRect(NSCurrentGraphicsPort(),rect);
133 CGContextRestoreGState(context);
136 void NSRectFillListUsingOperation(const NSRect *rects,int count,NSCompositingOperation operation) {
137 CGContextRef context=NSCurrentGraphicsPort();
138 CGContextSaveGState(context);
139 CGContextSetBlendMode(context,blendModeForCompositeOp(operation));
140 CGContextFillRects(NSCurrentGraphicsPort(),rects,count);
141 CGContextRestoreGState(context);
144 void NSRectFillUsingOperation(NSRect rect,NSCompositingOperation op) {
145 NSRectFillListUsingOperation(&rect,1,op);
148 void NSFrameRectWithWidth(NSRect rect,CGFloat width) {
149 NSFrameRectWithWidthUsingOperation(rect,width,NSCompositeCopy);
152 void NSFrameRectWithWidthUsingOperation(NSRect rect,CGFloat width,NSCompositingOperation operation) {
153 CGContextRef context=NSCurrentGraphicsPort();
154 CGContextSaveGState(context);
155 CGContextSetBlendMode(context,blendModeForCompositeOp(operation));
158 edge[0].origin.x=rect.origin.x;
159 edge[0].origin.y=rect.origin.y;
160 edge[0].size.width=width;
161 edge[0].size.height=rect.size.height;
163 edge[1].origin.x=NSMaxX(rect)-width;
164 edge[1].origin.y=rect.origin.y;
165 edge[1].size.width=width;
166 edge[1].size.height=rect.size.height;
168 edge[2].origin.x=rect.origin.x+width;
169 edge[2].origin.y=rect.origin.y;
170 edge[2].size.width=rect.size.width-width*2;
171 edge[2].size.height=width;
173 edge[3].origin.x=rect.origin.x+width;
174 edge[3].origin.y=NSMaxY(rect)-width;
175 edge[3].size.width=rect.size.width-width*2;
176 edge[3].size.height=width;
178 CGContextFillRects(NSCurrentGraphicsPort(),edge,4);
179 CGContextRestoreGState(context);
182 void NSFrameRect(NSRect rect) {
183 CGContextStrokeRectWithWidth(NSCurrentGraphicsPort(),rect,1);
186 void NSDottedFrameRect(NSRect rect) {
187 [[NSColor blackColor] setFill];
188 /* Win32 has poor dashed line support...
190 DrawFocusRect produces dark spots for the gaps sometimes
191 If we use a brush, it becomes black&white, not black&transparent
192 The PS_DOT pen is not a single pixel dot.
194 Fortunately this is not used heavily...
196 if(rect.size.width<=0 || rect.size.height<=0)
199 NSRect rects[(int)rect.size.width+2+(int)rect.size.height+2];
201 int x,y,maxx=NSMaxX(rect),maxy=NSMaxY(rect);
204 for(x=rect.origin.x;x<maxx;x++,on=!on)
206 rects[count++]=NSMakeRect(x,rect.origin.y,1,1);
208 for(y=rect.origin.y;y<maxy;y++,on=!on)
210 rects[count++]=NSMakeRect(maxx-1,y,1,1);
212 for(x=maxx;--x>=rect.origin.x;on=!on)
214 rects[count++]=NSMakeRect(x,maxy,1,1);
216 for(y=maxy;--y>=rect.origin.y;on=!on)
218 rects[count++]=NSMakeRect(rect.origin.x,y,1,1);
220 CGContextFillRects(NSCurrentGraphicsPort(),rects,count);
225 static NSRect NSDrawColorRects(NSRect boundsRect,NSRect clipRect,const NSRect *sides,NSColor **colors,int count) {
226 CGContextRef graphicsPort=NSCurrentGraphicsPort();
228 CGContextSaveGState(graphicsPort);
229 CGContextClipToRect(graphicsPort,clipRect);
230 NSRectFillListWithColors(sides,colors,count);
231 CGContextRestoreGState(graphicsPort);
236 void NSDrawButton(NSRect rect,NSRect clipRect) {
244 if([[NSGraphicsContext currentContext] isFlipped]){
245 colors[0]=[NSColor blackColor];
246 rects[0].origin.y+=rect.size.height-1;
247 rects[0].size.height=1;
249 colors[1]=[NSColor blackColor];
250 rects[1].origin.x+=rect.size.width-1;
251 rects[1].size.width=1;
253 colors[2]=[NSColor darkGrayColor];
254 rects[2].origin.x+=1;
255 rects[2].size.width-=2;
256 rects[2].origin.y+=rect.size.height-2;
257 rects[2].size.height=1;
259 colors[3]=[NSColor darkGrayColor];
260 rects[3].origin.x+=rect.size.width-2;
261 rects[3].origin.y+=1;
262 rects[3].size.width=1;
263 rects[3].size.height-=2;
265 colors[4]=[NSColor whiteColor];
266 rects[4].size.height=1;
267 rects[4].size.width-=1;
269 colors[5]=[NSColor whiteColor];
270 rects[5].size.width=1;
271 rects[5].size.height-=1;
273 colors[6]=[NSColor controlColor];
274 rects[6].origin.x+=1;
275 rects[6].origin.y+=1;
276 rects[6].size.width-=3;
277 rects[6].size.height-=3;
280 colors[0]=[NSColor blackColor];
281 rects[0].size.height=1;
283 colors[1]=[NSColor blackColor];
284 rects[1].origin.x+=rect.size.width-1;
285 rects[1].size.width=1;
287 colors[2]=[NSColor darkGrayColor];
288 rects[2].origin.x+=1;
289 rects[2].origin.y+=1;
290 rects[2].size.width-=2;
291 rects[2].size.height=1;
293 colors[3]=[NSColor darkGrayColor];
294 rects[3].origin.x+=rect.size.width-2;
295 rects[3].origin.y+=2;
296 rects[3].size.width=1;
297 rects[3].size.height-=2;
299 colors[4]=[NSColor whiteColor];
300 rects[4].origin.y+=1;
301 rects[4].size.width=1;
302 rects[4].size.height-=1;
304 colors[5]=[NSColor whiteColor];
305 rects[5].origin.y+=rect.size.height-1;
306 rects[5].size.width-=1;
307 rects[5].size.height=1;
309 colors[6]=[NSColor controlColor];
310 rects[6].origin.x+=1;
311 rects[6].origin.y+=2;
312 rects[6].size.width-=3;
313 rects[6].size.height-=3;
316 NSDrawColorRects(rect,clipRect,rects,colors,7);
319 void NSDrawGrayBezel(NSRect rect, NSRect clipRect) {
327 if ([[NSGraphicsContext currentContext] isFlipped]) {
328 colors[0]=[NSColor whiteColor];
329 colors[1]=[NSColor controlShadowColor];
330 rects[1].size.width-=1;
331 rects[1].size.height-=1;
332 colors[2]=[NSColor blackColor];
333 rects[2].origin.x+=1;
334 rects[2].origin.y+=1;
335 rects[2].size.width-=3;
336 rects[2].size.height-=3;
337 colors[3]=[NSColor controlColor];
338 rects[3].origin.x+=2;
339 rects[3].origin.y+=2;
340 rects[3].size.width-=3;
341 rects[3].size.height-=3;
344 colors[0]=[NSColor whiteColor];
345 colors[1]=[NSColor controlShadowColor];
346 rects[1].origin.y+=1;
347 rects[1].size.width-=1;
348 rects[1].size.height-=1;
349 colors[2]=[NSColor blackColor];
350 rects[2].origin.x+=1;
351 rects[2].origin.y+=2;
352 rects[2].size.width-=3;
353 rects[2].size.height-=3;
354 colors[3]=[NSColor controlColor];
355 rects[3].origin.x+=2;
356 rects[3].origin.y+=1;
357 rects[3].size.width-=3;
358 rects[3].size.height-=3;
361 NSDrawColorRects(rect,clipRect,rects,colors,4);
365 void NSDrawWhiteBezel(NSRect rect, NSRect clipRect) {
373 if ([[NSGraphicsContext currentContext] isFlipped]) {
374 colors[0]=[NSColor whiteColor];
375 colors[1]=[NSColor controlShadowColor];
376 rects[1].size.height=1;
377 colors[2]=[NSColor controlShadowColor];
378 rects[2].size.width=1;
379 rects[2].size.height-=1;
380 colors[3]=[NSColor controlColor];
381 rects[3].origin.x+=1;
382 rects[3].origin.y+=1;
383 rects[3].size.width-=2;
384 rects[3].size.height-=2;
385 colors[4]=[NSColor blackColor];
386 rects[4].origin.x+=1;
387 rects[4].origin.y+=1;
388 rects[4].size.width-=2;
389 rects[4].size.height=1;
390 colors[5]=[NSColor blackColor];
391 rects[5].origin.x+=1;
392 rects[5].origin.y+=1;
393 rects[5].size.width=1;
394 rects[5].size.height-=3;
395 colors[6]=[NSColor whiteColor];
396 rects[6].origin.x+=2;
397 rects[6].origin.y+=2;
398 rects[6].size.width-=4;
399 rects[6].size.height-=4;
402 colors[0]=[NSColor whiteColor];
403 colors[1]=[NSColor controlShadowColor];
404 rects[1].origin.y+=rect.size.height;
405 rects[1].size.height=1;
406 colors[2]=[NSColor controlShadowColor];
407 rects[2].size.width=1;
408 rects[2].origin.y+=1;
409 rects[2].size.height-=1;
410 colors[3]=[NSColor controlColor];
411 rects[3].origin.x+=1;
412 rects[3].origin.y+=1;
413 rects[3].size.width-=2;
414 rects[3].size.height-=2;
415 colors[4]=[NSColor blackColor];
416 rects[4].origin.x+=1;
417 rects[4].origin.y+=rect.size.height-1;
418 rects[4].size.width-=2;
419 rects[4].size.height=1;
420 colors[5]=[NSColor blackColor];
421 rects[5].origin.x+=1;
422 rects[5].origin.y+=2;
423 rects[5].size.width=1;
424 rects[5].size.height-=3;
425 colors[6]=[NSColor whiteColor];
426 rects[6].origin.x+=2;
427 rects[6].origin.y+=2;
428 rects[6].size.width-=4;
429 rects[6].size.height-=3;
432 NSDrawColorRects(rect,clipRect,rects,colors,7);
435 void NSDrawDarkBezel(NSRect rect,NSRect clipRect){
436 NSDrawGrayBezel(rect,clipRect);
439 void NSDrawLightBezel(NSRect rect,NSRect clipRect){
440 NSDrawWhiteBezel(rect,clipRect);
443 void NSDrawGroove(NSRect rect, NSRect clipRect) {
451 if ([[NSGraphicsContext currentContext] isFlipped]) {
452 colors[0]=[NSColor controlShadowColor];
453 colors[1]=[NSColor whiteColor];
454 rects[1].origin.x+=1;
455 rects[1].origin.y+=1;
456 colors[2]=[NSColor controlShadowColor];
457 rects[2].origin.x+=2;
458 rects[2].origin.y+=2;
459 rects[2].size.width-=3;
460 rects[2].size.height-=3;
461 colors[3]=[NSColor controlColor];
462 rects[3].origin.x+=2;
463 rects[3].origin.y+=2;
464 rects[3].size.width-=4;
465 rects[3].size.height-=4;
468 colors[0]=[NSColor controlShadowColor];
469 colors[1]=[NSColor whiteColor];
470 rects[1].origin.x+=1;
471 rects[1].size.height-=1;
472 colors[2]=[NSColor controlShadowColor];
473 rects[2].origin.x+=2;
474 rects[2].origin.y+=1;
475 rects[2].size.width-=3;
476 rects[2].size.height-=3;
477 colors[3]=[NSColor controlColor];
478 rects[3].origin.x+=2;
479 rects[3].origin.y+=2;
480 rects[3].size.width-=4;
481 rects[3].size.height-=4;
484 NSDrawColorRects(rect,clipRect,rects,colors,4);
487 void NSDrawWindowBackground(NSRect rect) {
488 [[NSColor windowBackgroundColor] setFill];
492 NSRect NSDrawTiledRects(NSRect bounds,NSRect clip,const NSRectEdge *sides,const float *grays,int count) {
496 void NSHighlightRect(NSRect rect) {
497 [[NSColor highlightColor] setFill];
498 CGContextFillRect(NSCurrentGraphicsPort(),rect);
501 void NSCopyBits(int gState,NSRect rect,NSPoint point) {
502 CGContextCopyBits(NSCurrentGraphicsPort(),rect,point,gState);
506 [[NSDisplay currentDisplay] beep];
509 void NSEnableScreenUpdates(void) {
512 void NSDisableScreenUpdates(void) {
515 void NSShowAnimationEffect(NSAnimationEffect effect,NSPoint center,NSSize size,id delegate,SEL didEndSelector,void *context) {
516 [NSPoofAnimation poofAtLocation:center size:size animationDelegate:delegate didEndSelector:didEndSelector contextInfo:context];