//
//  TestView.m
//  CocoaRendering
//
//  Created by Markus Stange on 04.10.08.
//  Copyright 2008 __MyCompanyName__. All rights reserved.
//



#import "TestView.h"


@implementation NSCell(ControlTintWorkaround)
- (NSControlTint)_realControlTint { return [self controlTint]; }
@end;

@implementation NSView(SearchfieldDrawingWorkaround)
- (NSText*)currentEditor { return nil; }
@end;

enum {
  kPushButton,
  kSquareButton,
  kCheckbox,
  kSearchfield,
  kDropdown
};

@implementation TestView

- (id)initWithFrame:(NSRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code here.
        isFlipped = YES;
    }
    return self;
}

- (void)   drawCell:(int)cellType
    withControlSize:(NSControlSize)controlSize
             inRect:(NSRect)rect
      flippedOnDraw:(BOOL)isFlippedOnDraw        /* changes the return value of this view's isFlipped method before drawing */
        inFocusView:(BOOL)useFocusView           /* otherwise, pass |self| to drawWithFrame:inView:. */
         withBuffer:(BOOL)useBuffer
          inNSImage:(BOOL)useNSImage             /* only has an effect when useBuffer */
 withContextSetting:(BOOL)setContext             /* only has an effect when !useBuffer */
 flipTransformOuter:(BOOL)useFlipTransform
flipTransformBuffer:(BOOL)useFlipTransformBuffer /* only has an effect when useBuffer */
{
  [NSGraphicsContext saveGraphicsState];
  if (useFlipTransform) {
    CGContextScaleCTM([[NSGraphicsContext currentContext] graphicsPort], 1.0f, -1.0f);
    CGContextTranslateCTM([[NSGraphicsContext currentContext] graphicsPort], 0.0f, -(2.0 * rect.origin.y + rect.size.height));
  }
  NSCell* cell;
  switch (cellType) {
    case kDropdown: {
      cell = [[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO];
    } break;
    case kCheckbox: {
      cell = [[NSButtonCell alloc] initTextCell:nil];
      [cell setButtonType:NSSwitchButton];
      [cell setState:NSOnState];
    } break;
    case kSearchfield: {
      cell = [[NSSearchFieldCell alloc] initTextCell:@""];
      [cell setBezelStyle:NSTextFieldRoundedBezel];
      [cell setBezeled:YES];
      [cell setEditable:YES];
    } break;
    case kPushButton: {
      cell = [[NSButtonCell alloc] initTextCell:nil];
      [cell setButtonType:NSMomentaryPushInButton];
      [cell setHighlightsBy:NSPushInCellMask];
      [cell setBezelStyle:NSRoundedBezelStyle];
    } break;
    case kSquareButton: {
      cell = [[NSButtonCell alloc] initTextCell:nil];
      [cell setButtonType:NSMomentaryPushInButton];
      [cell setHighlightsBy:NSPushInCellMask];
      [cell setBezelStyle:NSShadowlessSquareBezelStyle];
    } break;
  }
  [cell setControlSize:controlSize];
  isFlipped = isFlippedOnDraw;
  NSGraphicsContext* savedContext = [NSGraphicsContext currentContext];
  int w = rect.size.width + 20;  // use 10px padding on all four sides
  int h = rect.size.height + 20;
  CGContextRef bufferCtx;
  NSImage* bufferImage;
  NSRect drawRect = rect;
  if (useBuffer) {
    drawRect = NSMakeRect(10, 10, rect.size.width, rect.size.height);
    if (useNSImage) {
      bufferImage = [[NSImage alloc] initWithSize:NSMakeSize(w, h)];
      [bufferImage setFlipped:isFlippedOnDraw]; // In this case, isFlippedOnDraw makes a difference because that's what [[NSView focusView] isFlipped] will return after locking focus on the image
      [bufferImage lockFocus]; // affects [NSView focusView]
    } else {
      CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
      bufferCtx = CGBitmapContextCreate(NULL, w, h, 8, w * 4, rgb, kCGImageAlphaPremultipliedFirst);
      CGColorSpaceRelease(rgb);
      [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:bufferCtx flipped:YES]]; // flipped: YES or NO makes no difference
    }
    if (useFlipTransformBuffer) {
      CGContextScaleCTM([[NSGraphicsContext currentContext] graphicsPort], 1.0f, -1.0f);
      CGContextTranslateCTM([[NSGraphicsContext currentContext] graphicsPort], 0.0f, -h);
    }
  } else if (setContext) {
    [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:[[NSGraphicsContext currentContext] graphicsPort] flipped:YES]]; // flipped: YES or NO makes no difference
  }
  if (useFocusView) {
    [cell drawWithFrame:drawRect inView:[NSView focusView]];
  } else {
    [cell drawWithFrame:drawRect inView:self];
  }
  if (useBuffer ? !useNSImage : setContext) {
    [NSGraphicsContext setCurrentContext:savedContext];
  }
  if (useBuffer) {
    if (useNSImage) {
      [bufferImage unlockFocus];
      [bufferImage drawInRect:NSMakeRect(rect.origin.x - 10, rect.origin.y - 10, w, h) fromRect:NSMakeRect(0, 0, w, h) operation:NSCompositeSourceOver fraction:1.0];
      [bufferImage release];
    } else {
      CGImageRef img = CGBitmapContextCreateImage(bufferCtx);
      CGContextDrawImage([[NSGraphicsContext currentContext] graphicsPort], CGRectMake(rect.origin.x - 10, rect.origin.y - 10, w, h), img);
      CGImageRelease(img);
      CGContextRelease(bufferCtx);
    }
  }
  [cell release];
  [NSGraphicsContext restoreGraphicsState];
}
          

- (void)drawRect:(NSRect)rect {
  NSControlSize sizes[3] = { NSMiniControlSize, NSSmallControlSize, NSRegularControlSize };
  int cellType;
  for (cellType = 0; cellType < 5; ++cellType) {
    NSControlSize controlSize;
    for (controlSize = 0; controlSize < 3; ++controlSize) {
      int y = 10 + 80 * cellType + 25 * controlSize;
      int i = 0;
      // 1. Straightforward drawing to the screen - no context setup, no transforms, nothing
      [self drawCell:cellType withControlSize:sizes[controlSize] inRect:NSMakeRect(10 + 85 * i++, y, 80, 16 + 3 * controlSize) flippedOnDraw:YES inFocusView:NO  withBuffer:NO  inNSImage:NO  withContextSetting:NO  flipTransformOuter:NO  flipTransformBuffer:NO];
      // 2. Currently implemented way of context-free drawing: With setContext, using [NSView focusView] and with outer flip transform (with the difference that we don't flip checkboxes on 10.4)
      [self drawCell:cellType withControlSize:sizes[controlSize] inRect:NSMakeRect(10 + 85 * i++, y, 80, 16 + 3 * controlSize) flippedOnDraw:YES inFocusView:YES withBuffer:NO  inNSImage:NO  withContextSetting:YES flipTransformOuter:YES flipTransformBuffer:NO];
      // 3. Currently implemented way of drawing into contexts: Using [NSView focusView] and with outer flip transform (with the difference that we don't flip checkboxes on 10.4)
      [self drawCell:cellType withControlSize:sizes[controlSize] inRect:NSMakeRect(10 + 85 * i++, y, 80, 16 + 3 * controlSize) flippedOnDraw:YES inFocusView:YES withBuffer:YES inNSImage:NO  withContextSetting:NO  flipTransformOuter:YES flipTransformBuffer:NO];
      // 4. Drawing into an NSImage: Easy to get right, complicated code
      [self drawCell:cellType withControlSize:sizes[controlSize] inRect:NSMakeRect(10 + 85 * i++, y, 80, 16 + 3 * controlSize) flippedOnDraw:YES inFocusView:YES withBuffer:YES inNSImage:YES withContextSetting:NO  flipTransformOuter:YES flipTransformBuffer:NO];
      // 5. Proposed new way of drawing without a context: don't use [NSView focusView], no flip transform
      [self drawCell:cellType withControlSize:sizes[controlSize] inRect:NSMakeRect(10 + 85 * i++, y, 80, 16 + 3 * controlSize) flippedOnDraw:YES inFocusView:NO  withBuffer:NO  inNSImage:NO  withContextSetting:YES flipTransformOuter:NO  flipTransformBuffer:NO];
      // 6. Proposed new way of drawing into a context: don't use [NSView focusView], two flip transforms
      [self drawCell:cellType withControlSize:sizes[controlSize] inRect:NSMakeRect(10 + 85 * i++, y, 80, 16 + 3 * controlSize) flippedOnDraw:YES inFocusView:NO  withBuffer:YES inNSImage:NO  withContextSetting:NO  flipTransformOuter:YES flipTransformBuffer:YES];
      // 7. Entertaining drawing bugs
      [self drawCell:cellType withControlSize:sizes[controlSize] inRect:NSMakeRect(10 + 85 * i++, y, 80, 16 + 3 * controlSize) flippedOnDraw:NO  inFocusView:NO  withBuffer:NO  inNSImage:NO  withContextSetting:NO  flipTransformOuter:NO  flipTransformBuffer:NO];
      [self drawCell:cellType withControlSize:sizes[controlSize] inRect:NSMakeRect(10 + 85 * i++, y, 80, 16 + 3 * controlSize) flippedOnDraw:YES inFocusView:YES withBuffer:NO  inNSImage:NO  withContextSetting:YES flipTransformOuter:NO  flipTransformBuffer:NO];
      [self drawCell:cellType withControlSize:sizes[controlSize] inRect:NSMakeRect(10 + 85 * i++, y, 80, 16 + 3 * controlSize) flippedOnDraw:YES inFocusView:NO  withBuffer:YES inNSImage:NO  withContextSetting:NO  flipTransformOuter:YES flipTransformBuffer:NO];
    }
  }
}

- (BOOL)isFlipped {
  return isFlipped;
}

@end
