NSButton with CALayer flips the image when clicked - objective-c

I've got an NSButton with an attached CALayer and an image set on it. When I click the button, the image flips!
_zoomButton = [NSButton new];
[_zoomButton setBordered:NO];
[_zoomButton setButtonType:NSMomentaryChangeButton];
[_zoomButton setTitle:#""];
[_zoomButton setWantsLayer:YES];
[_zoomButton setImage:s_zoomImage];
[_zoomButton sizeToFit];
s_zoomImage is just an NSImage loaded from resources:
namespace
{
NSImage *s_zoomImage; // No static variables in Objective-C.
}
+ (void)initialize
{
[super initialize];
NSString *const zoomImagePath = [[NSBundle mainBundle] pathForResource:#"Zoom.png" ofType:nil];
s_zoomImage = [[[NSImage alloc] initWithContentsOfFile:zoomImagePath] autorelease];
}
At first the button displays correctly, but if I click it, the image (s_zoomImage) flips vertically! Any ideas?

Related

cocoa detect object in mouse clicked

I created a custom object (NSImageView) to display images and I use addSubview: self.view to add
I want to determine if the mouse click in it.
How do I do?
Thank you.
NSImage *Image = [NSImage imageNamed:#"oneimage.jpg"];
NSImageView *ImageView = [[NSImageView alloc] init];
[ImageView setImage:Image];
[self.window addSubview:ImageView];
[ImageView_IconToAdd setAcceptsTouchEvents:YES];
[ImageView_IconToAdd setWantsRestingTouches:YES];
-(void)mouseDragged:(NSEvent *)theEvent {
id clickedObject = [self hitTest:[theEvent locationInWindow]];
if ([clickedObject isKindOfClass:[NSImageView class]]) {
NSLog(#"Clicked an ImageView");
} else if ([clickedObject isKindOfClass:[NSView class]]) {
NSLog(#"Clicked a WebView");
}
}
But error:
No visible #interface for 'WindowImage' declares the selector 'hitTest:'
And can't get Object!

Can not adjust UIPopupController to display images

In my application (code listed below), I use a popover to display a series of colors that the user can choose. These colors are used for the color of the drawing they are completing above. I am trying to modify the popover to work the same way, except for this time I would want to display images (the images are saved in the application's documents folder as png files) instead of blocks of color. Listed below is the working code for the color selector popover. ColorGrid is a UIview which contains an NSArray Colors, as well as two NSUIntegers columnCount and rowCount. I have tried to replace the items in the colors array with UIImages of the png files, as well as UIImageViews but I have not been able to get a successful result (or a compilable one). Listed below is the working code. Could anyone show me how I can change the UIColor items to the images to show them in the grid?
- (IBAction)popoverStrokeColor:(id)sender {
StrokeColorController *scc = [[[StrokeColorController alloc] initWithNibName:#"SelectColorController" bundle:nil] autorelease];
scc.selectedColor = self.strokeColor;
[self doPopoverSelectColorController:scc sender:sender];
}
- (void)doPopoverSelectColorController:(SelectColorController*)scc sender:(id)sender {
[self setupNewPopoverControllerForViewController:scc];
scc.container = self.currentPopover;
self.currentPopover.popoverContentSize = scc.view.frame.size;
scc.colorGrid.columnCount = 2;
scc.colorGrid.rowCount = 3;
scc.colorGrid.colors = [NSArray arrayWithObjects:
//put the following below back in after testing
[UIColor blackColor],
[UIColor blueColor],
[UIColor redColor],
[UIColor greenColor],
[UIColor yellowColor],
[UIColor orangeColor],
//[UIColor purpleColor],
// [UIColor brownColor],
// [UIColor whiteColor],
// [UIColor lightGrayColor],
//[UIColor cyanColor],
//[UIColor magentaColor],
nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(colorSelectionDone:) name:ColorSelectionDone object:scc];
[self.currentPopover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; //displays the popover and anchors it to the button
}
Thanks for your help. I am new to objective-c.
edit - heres the function with my attempt to insert the images instead of the colors
- (void)doPopoverSelectColorController:(SelectColorController*)scc sender:(id)sender {
[self setupNewPopoverControllerForViewController:scc];
scc.container = self.currentPopover;
self.currentPopover.popoverContentSize = scc.view.frame.size;
// these have to be set after the view is already loaded (which happened
// a couple of lines ago, thanks to scc.view...
scc.colorGrid.columnCount = 2;
scc.colorGrid.rowCount = 3;
//here we need to get the UIImage items to try to put in the array.
NSArray *pathforsave = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [pathforsave objectAtIndex:0];
//here we need to add the file extension onto the file name before we add the name to the path
//[fileName appendString:#".hmat"];
NSString *strFile = [documentDirectory stringByAppendingPathComponent:#"test.png"];
NSString *strFile1 = [documentDirectory stringByAppendingPathComponent:#"test1.png"];
NSString *strFile2 = [documentDirectory stringByAppendingPathComponent:#"test2.png"];
NSString *strFile3 = [documentDirectory stringByAppendingPathComponent:#"test3.png"];
NSString *strFile4 = [documentDirectory stringByAppendingPathComponent:#"test4.png"];
NSString *strFile5 = [documentDirectory stringByAppendingPathComponent:#"test5.png"];
//now for the Images
UIImage *image = [ UIImage imageWithContentsOfFile: strFile];
UIImage *image1 = [ UIImage imageWithContentsOfFile: strFile1];
UIImage *image2 = [ UIImage imageWithContentsOfFile: strFile2];
UIImage *image3 = [ UIImage imageWithContentsOfFile: strFile3];
UIImage *image4 = [ UIImage imageWithContentsOfFile: strFile4];
UIImage *image5 = [ UIImage imageWithContentsOfFile: strFile5];
UIImageView *imageview = [[[UIImageView alloc] initWithImage:image] autorelease];
[self.view addSubview:imageview];
UIImageView *imageview1 = [[[UIImageView alloc] initWithImage:image1] autorelease];
[self.view addSubview:imageview1];
UIImageView *imageview2 = [[[UIImageView alloc] initWithImage:image2] autorelease];
[self.view addSubview:imageview2];
UIImageView *imageview3 = [[[UIImageView alloc] initWithImage:image3] autorelease];
[self.view addSubview:imageview3];
UIImageView *imageview4 = [[[UIImageView alloc] initWithImage:image4] autorelease];
[self.view addSubview:imageview4];
UIImageView *imageview5 = [[[UIImageView alloc] initWithImage:image5] autorelease];
[self.view addSubview:imageview5];
imageview.image = image;
imageview1.image = image1;
imageview2.image = image2;
imageview3.image = image3;
imageview4.image = image4;
imageview5.image = image5;
scc.colorGrid.colors = [NSArray arrayWithObjects:
// When attempting to add the images like this - get the error identified expected
// after the e in image, at the end bracket. Putting a * does nothing to change the error
[image],
// When adding one of the Imageviews, i get the same error as above
//below is how I attempted to add it
[imageView],
//
nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(colorSelectionDone:) name:ColorSelectionDone object:scc];
[self.currentPopover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; //displays the popover and anchors it to the button
}
Remove your square brackets around image and/or imageView :
scc.colorGrid.colors = [NSArray arrayWithObjects:
// Not : [image] but
image,
// or
imageView,
// Not : [imageView],
nil];

Saving entire NSView contents, which is inside an NSScrollView

I'm trying to save contents of an NSView as an image, but, only the image visible inside the scrollview is saved.
Here is the actual image loaded in the view:
.
But this is how I'm able to save the image:
Is there any way to save the entire image in the NSView?
This is how I'm saving my NSView subclass:
- (void)save
{
[self lockFocus];
NSBitmapImageRep* rep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:[self bounds]];
[self unlockFocus];
NSData* data = [rep representationUsingType:NSPNGFileType properties:nil];
NSString* string = NSHomeDirectory();
NSString* pth1 = [string stringByAppendingPathComponent:#"ttx.png"];
[data writeToFile:pth1 atomically:YES];
}
This method is in the View i want to save.
Use -[NSView cacheDisplayInRect:toBitmapImageRep:]
NSBitmapImageRep* rep = [self bitmapImageRepForCachingDisplayInRect:self.bounds];
[self cacheDisplayInRect:self.bounds toBitmapImageRep:rep];

Save multiple custom UIImageViews

I was recently examining the project "Demo Photo Board" found here.
This is a simple demonstration of adding UIImageViews to the screen that have UIGestureRecognizers added to them...allowing the user to manipulate the various UIImageViews.
I add the view like so:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
imageview = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, image.size.width, image.size.height)];
imageview.userInteractionEnabled = YES;
[imageview setImage:image];
UIPinchGestureRecognizer *pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(scale:)];
[pinchRecognizer setDelegate:self];
[imageview addGestureRecognizer:pinchRecognizer];
UIRotationGestureRecognizer *rotationRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotate:)];
[rotationRecognizer setDelegate:self];
[imageview addGestureRecognizer:rotationRecognizer];
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(move:)];
[panRecognizer setMinimumNumberOfTouches:1];
[panRecognizer setMaximumNumberOfTouches:1];
[panRecognizer setDelegate:self];
[imageview addGestureRecognizer:panRecognizer];
[self.view addSubview:imageview]; }
I can even save the view like so:
NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:[NSKeyedArchiver archivedDataWithRootObject:imageview] forKey:#"imageViewSaved"];
Now my question: The following method saves only the last imageview added to the screen. Anyone know how to save all of the imageviews that are on the screen...if the user adds more than one?
I really don't think you want to be saving the entire UIImageView object to the user defaults. Instead, try saving a list of UIImage objects, which will be much more lightweight. (And which make much more sense to serialize.)
You can do this like so:
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
NSArray *savedArray = [defs objectForKey:#"SAVED_IMAGES"];
// Create a mutable version in case the serialized copy is an NSArray
NSMutableArray *mutableImages = savedArray ? [NSMutableArray arrayWithArray:savedArray] : [NSMutableArray array];
[mutableImages addObject:image];
[defs setObject:mutableImages forKey:#"SAVED_IMAGES"];
[defs save];
To distinguish the UIImageViews on the screen you can do the following.
Define the start ImageView Tag number
#define kImageViewTag 3000
Define an instance var for number of images added to the screen.
NSUInteger numberOfImage = 0
Whenever you create a new UIImageView, increase the count and add it with the kImageViewTag and assign it to the tag property.
imageview = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, image.size.width, image.size.height)];
imageview.userInteractionEnabled = YES;
[imageview setImage:image];
numberOfImage += 1;
imageView.tag = kImageViewTag + numberOfImage;
Whenever you enumerate the screen subviews, if the class is UIImageView with the tag >= kImageViewTag, you know those are the images added to the screen from the UIImagePickerController.

long delay when calling cocoa method

I have a method for saving the contents of a UIScrollView with a user-supplied filename.
Everything works fine, except that there is a long delay when the user taps the "Save" button and the method is called. I can't work out what's calling the delay, nor find a way to indicate to the user that everything is ok, we have not crashed!
I thought the delay was occurring during the renderInContext, but it seems to be happening a lot earlier, when there is not much else going on.
Here is the troublesome method:
- (void)captureViewImage {
NSLog(#"captureViewImage called!");
// long delay happens here!
fileNamer.title = #"Preparing to save...";
// get user's file name
NSString *fileName = fileNamer.fileNameField.text;
// dismiss keyboard
[fileNamer.fileNameField resignFirstResponder];
// dismiss modal view
[self dismissFileNamingFormSheet];
CGRect oldFrame = mainScrollView.frame;
// capture off-screen content
mainScrollView.frame = CGRectMake(0, 0, 1024, 1432);
// make screenshot
UIGraphicsBeginImageContext(mainScrollView.bounds.size);
[mainScrollView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *screenImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// save screenshot in docs dir
NSData *pngData = UIImagePNGRepresentation(screenImg);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
[pngData writeToFile:[documentsDir stringByAppendingPathComponent:fileName]
options:NSDataWritingAtomic error:nil];
// revert scroll view
mainScrollView.frame = oldFrame;
}
fileNamer is a custom class that throws up a UIModalPresentationFormSheet asking the user to supply a name for the file. It looks like this:
#implementation FileNamingViewController
#synthesize fileNameField, newFileName;
- (id)initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil parent:(TestDriveViewController *) myParent {
if (self == [super initWithNibName:#"FileNamingViewController" bundle:nil]) {
UIBarButtonItem *rightButton = [[UIBarButtonItem alloc]
initWithTitle:#"Save"
style:UIBarButtonItemStyleDone
target:myParent
action:#selector(captureViewImage)];
self.navigationItem.rightBarButtonItem = rightButton;
[rightButton release];
UIBarButtonItem *leftButton = [[UIBarButtonItem alloc]
initWithTitle:#"Cancel"
style:UIBarButtonItemStyleBordered
target:myParent
action:#selector(dismissFileNamingFormSheet)];
self.navigationItem.leftBarButtonItem = leftButton;
[leftButton release];
self.title = #"Save As?";
}
return self;
}
// UITextFieldDelegate
- (void)textFieldDidEndEditing:(UITextField *)textField {
[fileNameField resignFirstResponder];
}
- (void)viewDidLoad {
[fileNameField becomeFirstResponder];
[super viewDidLoad];
}
fileNamer is initialized and released as follows:
- (void)presentFileNamingFormSheet {
fileNamer = [[FileNamingViewController alloc]
initWithNibName:nil
bundle:nil
parent:self];
fileNamingNavCtrl = [[UINavigationController alloc]
initWithRootViewController:fileNamer];
fileNamingNavCtrl.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentModalViewController:fileNamingNavCtrl
animated:YES];
// resize modal form sheet
fileNamingNavCtrl.view.superview.frame = CGRectMake(0, 0, 540, 115);
// reposition modal form sheet
CGPoint position = CGPointMake(self.view.center.x, self.view.center.y - 50);
fileNamingNavCtrl.view.superview.center = position;
}
- (void)dismissFileNamingFormSheet {
[fileNamer release];
[fileNamingNavCtrl release];
[self dismissModalViewControllerAnimated:YES];
}
Output from Time Profiler:
Running (Self) Symbol Name
1109.0ms 37.0% argb32_image_mark_rgb32
328.0ms 10.9% blkclr
171.0ms 5.7% lo_alltraps
134.0ms 4.4% pmap_enter
116.0ms 3.8% png_write_find_filter
102.0ms 3.4% pmap_remove_range
55.0ms 1.8% pmap_get_mapwindow
47.0ms 1.5% vm_page_lookup
47.0ms 1.5% ml_set_interrupts_enabled
43.0ms 1.4% vm_page_grab
38.0ms 1.2% OSAddAtomic64
34.0ms 1.1% hw_lock_to
31.0ms 1.0% alphaProviderGetBytes
30.0ms 1.0% hw_lock_unlock
26.0ms 0.8% png_read_filter_row
25.0ms 0.8% deflateInit_
23.0ms 0.7% vm_map_lookup_entry
23.0ms 0.7% adler32
22.0ms 0.7% memory_object_recover_named
I found out what was causing this. The image I was saving contained a lot of transparent views. For example, I had a lot of UIButtons which had an alpha value of 0.05 to make them more or less disappear. I didn't realise I could just set the button type to custom to make it invisible (I created the view along time ago). Once I set everything in my image view to have an alpha value of 1.0, the saving process became a lot quicker.