views:

1438

answers:

2

I have a simple Obj C program that, at the moment, lets you load an image, draws it up, and theoretically should let you zoom and rotate. I'm using NSAffineTranslations.

I want the image to be locked to the upper left (As opposed to the PS/PDF standard of lower left), so I'm using isFlipped, and calling [afTrans scaleXBy:1.0 yBy:-1.0];

The problem is that for some reason, after the first time my drawRect is called, the transformation doesn't happen.

When I load an image, it comes up, and looks correct. If I change the size of the window (Which calls drawRect), the image draws, but is upside-down and reversed. This means that the transformation didn't take effect. I don't see any differences in any of the data the 2nd time through.

here is a stripped down version of the code:

- (void)drawRect:(NSRect)rect 
{
    // Drawing code here.

//    NSLog(@"window type: %d", [[self window] backingType]);
   NSAffineTransform *afTrans = [[NSAffineTransform alloc] init];
   NSGraphicsContext *context = [NSGraphicsContext currentContext];
   NSSize sz;
   NSRect windowFrame = [[self window] frame];
   NSRect cv =[[[self window] contentView] frame];
   float deltaX, deltaY;
   NSSize superSize = [[self superview] frame].size;
   float height, width, sHeight, sWidth;

   NSRect imageRect;

   sz = [ image size];
   imageRect.size = sz;
   imageRect.origin = NSZeroPoint;

   height = sz.height  ;
   width = sz.width  ;

//    sHeight and sWidth are the hieght and with of the super-view. ie,
//    the size of the whole window view including the space for the
//    scroll bars, etc, but not including the panel or the borders,
   sHeight = superSize.height;
   sWidth = superSize.width;

   [context saveGraphicsState];

   deltaX = 0;
   deltaY = 0;

   deltaY += height; // account for flipping

   [afTrans translateXBy:deltaX yBy:deltaY];

   [afTrans scaleXBy:1.0 yBy:-1.0];

   [afTrans concat];

   NSRect drawingRect = imageRect;
   NSRect frame = imageRect;
   [self setFrame:frame];

   [image drawInRect:drawingRect
         fromRect:imageRect
         operation:NSCompositeSourceOver
         fraction:1];

   [afTrans release];
   [context restoreGraphicsState];
}

ETA: here's some more code that MIGHT be relevant.

-(void )setImage:( NSImage * )newImage
{
    [newImage retain];
    [image release];

    rotation = 0;

    zoom = 1.0;

    image = newImage;
    NSSize imageSize = [newImage size];
    NSRect tFrame = [self frame];
    tFrame = [[self window] frame];

    tFrame.size.width = MAX(tFrame.size.width, imageSize.width);
    tFrame.size.height = MAX(tFrame.size.height, imageSize.height);
    [self setFrame:tFrame];

    [self setNeedsDisplay:YES];
}
+1  A: 

Assuming you're not stripping out code that changes stuff, watch out if you're drawing the image elsewhere. Toolbar items, tables and so on may well change the -flipped property of the image, causing it to draw incorrectly.

Try this around your image drawing line:

BOOL wasFlipped = [image isFlipped];
[image setFlipped:[self isFlipped]];
[image drawInRect:drawingRect
    fromRect:imageRect
   operation:NSCompositeSourceOver
    fraction:1];
[image setFlipped:wasFlipped];

See if that helps. If it does, look elsewhere in your code for something changing the image's flipped property and not putting it back.

iKenndac
the isFlipped method isn't changing, it always returns YES.when I add this code (which always sets the flipped to 1, draws it, andsets it back to 0) it starts up UPSIDE DOWN, and then flips correctly when I make it re-draw.WTH is going on here?
Brian Postow
There must be something else going on — I pasted your code above into a new NSView class and the image draws correctly all the time. Are you setting the isFlipped property of the view itself in a way other than hard-returning YES in the view's isFlipped? Is so, the initial draw may be occurring before isFlipped is set.
iKenndac
Nope, I'm hardsetting YES in isFlipped... and it always seems to be set to YES, when I NSLog it... But the other issue is that I think it's the affineTransform, because it appears that the affine transform isn't happening when I change the window size. at least, It's doing the same thing as it does it I comment out the affine transform...
Brian Postow
Does it only happen *during* the live resize? If so, it could be live resize optimisations kicking in: http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaViewsGuide/Optimizing/Optimizing.html
iKenndac
+2  A: 

I'm not sure exactly what you're trying to achieve, but if you want to just draw an image in a NSView and keep it in the upper left, you can do something a bit simpler, in your NSView subclass:

- (BOOL)isFlipped
{
    return YES;
}

- (void)setImage:(NSImage *)newImage
{
    [newImage retain];
    [image release];
    image = newImage;

    [image setFlipped:YES];
    [self setNeedsDisplay:YES];
}

- (void)drawRect:(NSRect)rect
{
    [image drawAtPoint:NSZeroPoint fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1];

    // Or stretch image to fill view
    //[image drawInRect:[self bounds] fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1];
}

I was also able to get similar results with your code by getting rid of the [self setFrame:...]; calls in drawRect and setImage methods.

Zach Waugh
Well, I needed to add the setframes because otherwise the scroll bars weren't correct. However, this simplification worked! thanks!
Brian Postow