subclass a programmatically created NSImage - subclass

I programatically create an NSImage like this:
NSImageView *IconBox = [[NSImageView alloc] initWithFrame:CGRectMake(0, 0, 350, 300)];
NSImage *capper = [[NSImage alloc] initWithData:[self.superview dataWithPDFInsideRect:[self.superview bounds]]];
IconBox.image = capper;
[self addSubview:IconBox];
This Image gets main Part of my Window and i want to make this window draggable anywhere, i know i need to set mouseDownCanMoveWindow, but this doesn't work, while this applies to the Windoow, but while my Image is the main visible part of the Window you cannot access its background, so i need to tell the Image to drag the Window,
i read i need to subclass the NSImage and override this Method, but how can i subclass a programatically created NSImage?
I already created the Class Files in my Project, but how can i tell the newly created Image to use this custom class?

Figured it out:
Class snap = NSClassFromString(#"snapper");
object_setClass(IconBox, [snap class]);
This does the trick, also ithe default Method moveWindowByMouseDown didn't work either, but this snippet did:
In the NSImage Subclass:
-(void)mouseDragged:(NSEvent *)theEvent
{
CGFloat deltax = [theEvent deltaX];
CGFloat deltay = [theEvent deltaY];
NSRect frame = [[self window] frame];
frame.origin.x += deltax;
frame.origin.y -= deltay;
[[self window] setFrameOrigin:frame.origin];
}

Related

How do I add a NSButton to a CALayer?

I am trying to add a NSButton on a layer inside a IKImageBrowserCell object. I found this post helpful but it doesn't get into the crux.
I've already tried this:
- (CALayer *) layerForType:(NSString*) type
{
CGColorRef color;
//retrieve some usefull rects
NSRect frame = [self frame];
NSRect imageFrame = [self imageFrame];
NSRect relativeImageFrame = NSMakeRect(imageFrame.origin.x - frame.origin.x, imageFrame.origin.y - frame.origin.y, imageFrame.size.width, imageFrame.size.height);
/* foreground layer */
if(type == IKImageBrowserCellForegroundLayer){
//no foreground layer on place holders
if([self cellState] != IKImageStateReady)
return nil;
//create a foreground layer that will contain several childs layer
CALayer *layer = [CALayer layer];
layer.frame = CGRectMake(0, 0, frame.size.width, frame.size.height);
//add a checkbox to tell whether to upload this one or not
NSRect checkFrame = NSMakeRect( ( frame.size.width/2)-5 , frame.size.height - 19, 18,18);
NSButton *uploadCheckBox = [[NSButton alloc] initWithFrame:checkFrame];
[uploadCheckBox setButtonType:NSSwitchButton];
[layer addSublayer :[uploadCheckBox layer]];
return layer;
}
//(...)
return nil;
}
But unfortunately the button doesn't appear on the layer. I think the placement of the button is fine, since it's based on an example code from Apple's app. I've got a feeling that this line is wrong:
layer addSublayer :[uploadCheckBox layer]];, since I should be adding entire NSButton, not just it's bitmap representation (a layer). Any help greatly appreciated!
You cannot add a NSView inside a CALayer. You should create a new layer for your button purpose and add to your holding layer.

Programmatically add a close button to an NSWindow

I'd like to add a close button to an NSWindow programmatically. I can get the button to display, but there are no mouse-over or mouse-down effects. My "selector" never seems to get called when i click the button. I'm not really sure whats wrong and why this is so annoying.
Here is what I've been messing with:
closeButton = [NSWindow standardWindowButton:NSWindowCloseButton forStyleMask:self.styleMask];
NSView *themeFrame = [[self contentView] superview];
NSRect c = [themeFrame frame]; // c for "container"
NSRect aV = [closeButton frame]; // aV for "accessory view"
NSRect newFrame = NSMakeRect( c.size.width - aV.size.width - 5, // x position c.size.height - aV.size.height - 5, // y position aV.size.width, // width aV.size.height); // height
[closeButton setFrame:newFrame];
[themeFrame addSubview:closeButton];
[closeButton setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
[closeButton setEnabled:YES];
[closeButton setTarget:self];
[closeButton setAction:NSSelectorFromString(#"testClick:") ];
Where "testClick" is just a memeber function of my class and is defined as such:
- (void)testClick:(id)sender
The problem seems to be the call to:
[themeFrame addSubview:closeButton];
where the themeFrame is: [[self contentView] superview] Just adding the button to [self contentView] works, but I'd like it added to the titlebar.
No Interface Builder please...
Potential issue # 1)
The way you're calling "NSSelectorFromString" seems incorrect to me. I don't think you can pass parameters via this way in Objective C.
Try this:
[closeButton setAction: #selector(closeWindow:)];
and create a new "closeWindow:" action that looks like:
- (void) closeWindow: (id) sender;
which closes the window.
Potential issue # 2)
Instead of:
closeButton = [NSWindow standardWindowButton:NSWindowCloseButton forStyleMask:self.styleMask];
NSView *themeFrame = [[self contentView] superview];
Why not use:
NSWindow * parentWindow = [[self contentView] window];
if(parentWindow)
{
closeButton = [parentWindow standardWindowButton:NSWindowCloseButton forStyleMask:self.styleMask];
}

Drag window with NSImage as handle?

I am writing a mac app and have used this code to hide the window handle,
[self.window setStyleMask:NSBorderlessWindowMask];
Well this is great, but i still need a handle to move around the window, so is there a way to move around the window from another object like an NSImage, acting like the window handle?
The code for my image is in the .h,
#interface WOWAppDelegate : NSObject <NSApplicationDelegate> {
NSWindow *window;
IBOutlet NSImageView* winView;
}
and in the .m file,
- (void)awakeFromNib {
NSString *inFilePathwin = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"win.png"];
NSImage *winImage = [[[NSImage alloc] initWithContentsOfFile:inFilePathwin] autorelease];
[winView setImage:winImage];
}
So the image is working and showing so how do i link that function?
Hook the mouseDragged event on a NSView subview.
-(void)mouseDragged:(NSEvent *)theEvent
{
CGFloat deltax = [theEvent deltaX];
CGFloat deltay = [theEvent deltaY];
NSRect frame = [[self window] frame];
frame.origin.x += deltax;
frame.origin.y -= deltay;
[[self window] setFrameOrigin:frame.origin];
}
So
subclass NSView as XView
place your handle image in an instance of this view container.
Place the container where you want in the windows main view.
Use this snippet in XView to drag the window around.
Adjust the behaviour with the mouseDown and MouseUp events.

NSScrollView background image in Lion

I'm working on a Mac application with an NSScrollView, and I want the NSScrollView to have a custom background image. I used this code in the custom documentView NSView subclass:
- (void)drawRect:(NSRect)rect {
[[NSColor colorWithPatternImage:[NSImage imageNamed:#"wood.jpg"]] set];
NSRectFill(rect);
}
That displays a pattern image as a background for the documentView.
But now in Mac OS X Lion, the NSScrollView bounces when scrolling further than possible, showing ugly white space. How can I make the white space also being covered by the background image?
Instead of overriding drawRect:, use the scroll view's setBackgroundColor: method, passing the NSColor you created with the pattern image.
You should subclass use NSScrollView setBackgroundColor, but then you should subclass NSClipView like this to pin the texture origin to the top:
#implementation MYClipView
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect
{
if (self.drawsBackground)
{
NSGraphicsContext* theContext = [NSGraphicsContext currentContext];
[theContext saveGraphicsState];
float xOffset = NSMinX([self convertRect:[self frame] toView:nil]);
float yOffset = NSMaxY([self convertRect:[self frame] toView:nil]);
[theContext setPatternPhase:NSMakePoint(xOffset, yOffset)];
NSColor* color = self.backgroundColor;
[color set];
NSRectFill([self bounds]);
[theContext restoreGraphicsState];
}
// Note: We don't call [super drawRect:dirtyRect] because we don't need it to draw over our background.
}
+ (void)replaceClipViewInScrollView:(NSScrollView*)scrollView
{
NSView* docView = [scrollView documentView]; //[[scrollView documentView] retain];
MYClipView* newClipView = nil;
newClipView = [[[self class] alloc] initWithFrame:[[scrollView contentView] frame]];
[newClipView setBackgroundColor:[[scrollView contentView] backgroundColor]];
[scrollView setContentView:(NSClipView*)newClipView]; [scrollView setDocumentView:docView];
// [newClipView release];
// [docView release];
}
#end
And call + (void)replaceClipViewInScrollView:(NSScrollView*)scrollView with the NSScrollView instance.
Put your drawRect code in an NSScrollView subclass. In IB, change the NSScrollView to use your custom subclass instead of NSScrollView. Also make sure to uncheck Draw Background in the scroll view's attributes inspector.

CGGradient isn't visible (not using interface builder) and UIButtons can't be triggered

I have created a view that contains a CGGradient:
// Bar ContextRef
CGRect bar = CGRectMake(0, screenHeight-staffAlignment, screenWidth, barWidth);
CGContextRef barContext = UIGraphicsGetCurrentContext();
CGContextSaveGState(barContext);
CGContextClipToRect(barContext,bar);
// Bar GradientRef
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat components[16] = { 1.0,1.0,1.0,0.0, 0.0,0.0,0.0,1.0, 0.0,0.0,0.0,1.0, 1.0,1.0,1.0,0.0};
CGFloat locations[4] = {0.95,0.85,0.15,0.05};
size_t count = 4;
CGGradientRef gradientRef = CGGradientCreateWithColorComponents(colorSpace, components, locations, count);
// Draw Bar
CGPoint startPoint = {0.0,0.0};
CGPoint endPoint = {screenWidth,0.0};
CGContextDrawLinearGradient(barContext, gradientRef, startPoint, endPoint, 0);
CGContextRestoreGState(barContext);
This code is called in the drawRect method of the UIView. I then use a UIViewController to access the created view.
- (void)loadView {
MainPageView *mpView = [[MainPageView alloc] initWithFrame:[window bounds]];
[self setView:mpView];
[mpView release];
}
and displayed on the screen through the appDelegate:
mpViewController = [[MainPageViewController alloc] init];
[window addSubview:[mpViewController view]];
[window makeKeyAndVisible];
The UIView contains more objects, such as UIButtons, that are visible. I am assuming because they are added as a subview. But I can't work out how to add the CGGradient as a subview? Does it need to be? Is there another reason CGGradient is not visible?
I also don't get the functionality on the UIButtons. I guess that is because of where I have added the UIButtons to the view. Do the buttons need to be added in the UIViewController or the appDelegate to have functionality. Sorry to ask what would seem like simple questions but I am trying to accomplish the programming without the Interface Builder and material on that is scarce. If anyone could point me in the right direction on both these problems I would really appreciate it.
Thanks!
The functionality on the buttons was lost because the frame was too large but the buttons were still visible because the background was clearColor

Resources