NSAffine Transform Only Working on Scren

Discussion in 'Mac Programming' started by Senor Cuete, Nov 24, 2013.

  1. Senor Cuete macrumors regular

    Joined:
    Nov 9, 2011
    #1
    My Cocoa multiple document application draws some NSImages into NSView sub-classes. These are drawn to fill the frame / rect. I decided to draw these shadowed. Rather than change the frames of the view sub-classes in my .xib files and rewrite the code in their drawRect:methods, I decided to make their frames larger programmatically, draw the images transformed in the amount needed for the shadowing and restore the frames, etc. At the start of my drawRect method I save the frame and graphics context. After drawing the NSImages I restore them. This works perfectly when drawing to a window but when printing or saving, the frames are far from where they should be, offset by some large x in origin. For example creating an NS PrintOperation using the superview like this:

    Code:
    NSPrintOperation *op = [NSPrintOperation printOperationWithView: superview];
    creates a mess.

    Here is a code example:

    Code:
    - (void) drawRect: (NSRect)rect
    {
        drawingRect = rect;
    
        [NSGraphicsContext saveGraphicsState];
        NSRect savedFrame = [self frame];
        NSRect myFrame = [self frame];
        
        NSAffineTransform* xform = [NSAffineTransform transform];
        NSShadow* theShadow = [[[NSShadow alloc] init] autorelease];
        setDrawShadowed(&myFrame, self, xform, theShadow);
        //above function changes the frame and creates an NSAffineTransform so
        //the NSImage will be drawn where it belongs
    
        //Draw NSImage here
        
        [self setFrame: savedFrame];
        [NSGraphicsContext restoreGraphicsState];
        //or you could [xform invert]; to revert the transformation*/
    }
    Here is the function that creates the shadowing and the transform. This only works if drawing to the screen:

    Code:
    void setDrawShadowed(NSRect* frame, id classInstance, NSAffineTransform * xform, NSShadow *theShadow){
        frame->size.height += 4.0;
        frame->size.width += 4.0;
        frame->origin.y -= 3.0;
        [classInstance setFrame: *frame]; //set NSView frame to new frame
        //transform drawing coordinates in current context to draw correctly:
        [xform translateXBy: 0.0 yBy: 3.0];
        [xform concat];
        
        [theShadow setShadowOffset: NSMakeSize(3.0, -3.0)];
        [theShadow setShadowBlurRadius: 2.0];
        [theShadow setShadowColor: [[NSColor blackColor] colorWithAlphaComponent: 0.4]];
        [theShadow set];
    }
     
  2. Senor Cuete thread starter macrumors regular

    Joined:
    Nov 9, 2011
    #2
    Update

    If you change a the frame of a subclass of an NSView in its drawRect method and then restore it, it will display correctly when you are drawing to the screen but not while printing or saving:

    Code:
    NSRect savedFrame = [self frame];
    NSRect myFrame = [self frame];
    myFrame.origin.x += 1;
    [self setFrame: myFrame];
    [self setFrame: savedFrame];
    If you put these lines of code in your drawRect method it will draw correctly to the screen but when printing or saving, the frame of the NSView's subclass will be outside of the superclass's frame. For example if you print by overriding the superclass's

    Code:
    - (NSPrintOperation *)printOperationWithSettings:(NSDictionary *)printSettings error:(NSError **)outError
    method, the method
    Code:
    NSPrintOperation *op = [NSPrintOperation printOperationWithView: superview printInfo: tempPrintInfo];
    will generate an unusable NSPrintOperation; If changing the frame of an NSView subclass is not acceptable, why does Cocoa give you access to it?
     
  3. Senor Cuete thread starter macrumors regular

    Joined:
    Nov 9, 2011
    #3
    Changing Frame is the Problem

    If I alter my NSView subclass' frame using methods such as setFrame: or setFrameSize: programmatically, subsequent drawing to the screen will work but printing or saving won't. Either the NSImages won't appear or they will be in the wrong place. Yes I set the superview and my NSView subclass to need display and yes I reset the bounds and frame after drawing. Any Ideas?
     

Share This Page