iPad UIWebView position a UIPopoverController view at a href link coords - cocoa-touch

I'm hoping that this question isn't a stupid one but how does one go about positioning a UIPopoverController view over a UIWebView so that the popup view arrow points at the UIWebView link that was clicked to show it?
I'm using the delegate method;
-(BOOL) webView:(UIWebView *)inWeb shouldStartLoadWithRequest:(NSURLRequest *)inRequest navigationType:(UIWebViewNavigationType)inType {
if ( [[[inRequest URL] absoluteString] hasPrefix:#"myscheme:"] ) {
//UIPopoverController stuff here
return NO;
}
}
to capture and route the click but I'm unsure how to get the link coords to position the popup view.
Any help or pointer to relevant info would be very much appreciated.

I have a solution that works but I think there is a better way to do it.
I created a TouchableWebView that inherits from UIWebView and the save the touch position in the method hitTest. After that, you need to set a delegate for your webview and implement the method -webView:shouldStartLoadWithRequest:navigationType:
TouchableWebView.h :
#interface TouchableWebView : UIWebView {
CGPoint lastTouchPosition;
}
#property (nonatomic, assign) CGPoint lastTouchPosition;
TouchableWebView.m :
// I need to retrieve the touch position in order to position the popover
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
self.lastTouchPosition = point;
return [super hitTest:point withEvent:event];
}
In RootViewController.m :
[self.touchableWebView setDelegate:self];
// WebView delegate, when hyperlink clicked
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if (navigationType == UIWebViewNavigationTypeLinkClicked)
{
CGPoint touchPosition = [self.view convertPoint:self.touchableWebView.lastTouchPosition fromView:self.touchableWebView];
[self displayPopOver:request atPosition:touchPosition isOnCelebrityFrame:FALSE];
return FALSE;
}
return TRUE;
}
It's not good because documentation of UIWebView says that you shouldn't subclass it. I guess there is a nicer way but this does work. Did you find another solution ?

Give each link a unique ID and pass that ID to your Obj-C code via your "myscheme:" logic.
You can then determine the link's left & top offset in the UIWebView via Javascript calls:
NSString *leftJS = [NSString stringWithFormat:#"document.getElementById('%d').offsetLeft - scrollX", linkID];
NSInteger leftOffset = [[currentTextView stringByEvaluatingJavaScriptFromString:js] intValue];
NSString *topJS = [NSString stringWithFormat:#"document.getElementById('%d').offsetTop - scrollY", linkID];
NSInteger topOffset = [[currentTextView stringByEvaluatingJavaScriptFromString:js] intValue];
Subtracting scrollX/scrollY accounts for how much to the left or down the user has scrolled the UIWebView.
My understanding is that offsetLeft and offsetTop return the offsets of the element within its parent. So hopefully your links are at the top of the hierarchy instead of embedded in divs or else determining the offset gets more complicated.

For me, use of getBoundingClientRect() and convert it to CGRect works great.
NSString *js = [NSString stringWithFormat:#"JSON.stringify($(\"a[href='%#']\")[0].getBoundingClientRect())", [inRequest URL]];
// {top:, right:, bottom:, left:, width:, height:}
NSString *rectJson = [webView stringByEvaluatingJavaScriptFromString:js];
NSError *error = nil;
NSDictionary *rectDict = [NSJSONSerialization JSONObjectWithData:[rectJson dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:&error];
if (error) {
NSLog(#"json deserialization failed: %#\n%#", rectJson, error);
}
CGRect rect = CGRectMake([rectDict[#"left"] floatValue], [rectDict[#"top"] floatValue], [rectDict[#"width"] floatValue], [rectDict[#"height"] floatValue]);

Related

Drag and Drop from the Finder to a NSTableView weirdness

I'm trying to understand how best to impliment drag and drop of files from the Finder to a NSTableView which will subsequently list those files.
I've built a little test application as a proving ground.
Currently I have a single NSTableView with FileListController as it's datasourse. It's basically a NSMutableArray of File objects.
I'm trying to work out the best / right way to impliment the drag and drop code for the NSTableView.
My first approach was to subclass the NSTableView and impliment the required methods :
TableViewDropper.h
#import <Cocoa/Cocoa.h>
#interface TableViewDropper : NSTableView
#end
TableViewDropper.m
#import "TableViewDropper.h"
#implementation TableViewDropper {
BOOL highlight;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
// Initialization code here.
NSLog(#"init in initWithCoder in TableViewDropper.h");
[self registerForDraggedTypes:#[NSFilenamesPboardType]];
}
return self;
}
- (BOOL)performDragOperation:(id < NSDraggingInfo >)sender {
NSLog(#"performDragOperation in TableViewDropper.h");
return YES;
}
- (BOOL)prepareForDragOperation:(id)sender {
NSLog(#"prepareForDragOperation called in TableViewDropper.h");
NSPasteboard *pboard = [sender draggingPasteboard];
NSArray *filenames = [pboard propertyListForType:NSFilenamesPboardType];
NSLog(#"%#",filenames);
return YES;
}
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
{
highlight=YES;
[self setNeedsDisplay: YES];
NSLog(#"drag entered in TableViewDropper.h");
return NSDragOperationCopy;
}
- (void)draggingExited:(id)sender
{
highlight=NO;
[self setNeedsDisplay: YES];
NSLog(#"drag exit in TableViewDropper.h");
}
-(void)drawRect:(NSRect)rect
{
[super drawRect:rect];
if ( highlight ) {
//highlight by overlaying a gray border
[[NSColor greenColor] set];
[NSBezierPath setDefaultLineWidth: 18];
[NSBezierPath strokeRect: rect];
}
}
#end
The draggingEntered and draggingExited methods both get called but prepareForDragOperation and performDragOperation don't. I don't understand why not?
Next I thought I'll subclass the ClipView of the NSTableView instead. So using the same code as above and just chaging the class type in the header file to NSClipView I find that prepareForDragOperation and performDragOperation now work as expected, however the ClipView doesn't highlight.
If I subclass the NSScrollView then all the methods get called and the highlighting works but not as required. It's very thin and as expected round the entire NSTableView and not just the bit below the table header as I'd like.
So my question is what is the right thing to sublclass and what methods do I need so that when I peform a drag and drop from the Finder, the ClipView highlights properly and prepareForDragOperation and performDragOperation get called.
And also when performDragOperation is successful how can this method call a method within my FileListController telling it to create a new File object and adding it to the NSMutableArray?
Answering my own question.
It seems that subclassing the NSTableView (not the NSScrollView or the NSClipView) is the right way to go.
Including this method in the subclass :
- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender {
return [self draggingEntered:sender];
}
Solves the problem of prepareForDragOperation and performDragOperation not being called.
To allow you to call a method within a controller class, you make the delagate of your NSTextView to be the controller. In this case FileListController.
Then within performDragOperation in the NSTableView subclass you use something like :
NSPasteboard *pboard = [sender draggingPasteboard];
NSArray *filenames = [pboard propertyListForType:NSFilenamesPboardType];
id delegate = [self delegate];
if ([delegate respondsToSelector:#selector(doSomething:)]) {
[delegate performSelector:#selector(doSomething:)
withObject:filenames];
}
This will call the doSomething method in the controller object.
Updated example project code here.

Correct way to transition between collection view and paged detail view

Currently I have a uicollection view which displays a specific album in the users photos, (ALAssets library).
In my mainView.m I gather the pictures:
+ (ALAssetsLibrary *)defaultAssetsLibrary {
static dispatch_once_t pred = 0;
static ALAssetsLibrary *library = nil;
dispatch_once(&pred, ^{
library = [[ALAssetsLibrary alloc] init];
});
return library;
}
- (void)beginLoadingPhotoInfo {
...
[library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos
usingBlock:assetGroupEnumerator
failureBlock:^(NSError *error) {NSLog(#"Probs");}
];
}
Load them (the thumbnail version) all into the collection view and that all works well.
Then when a user selects a photo I call this prepareToSegue method: (still in mainView.m)
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([[segue identifier] isEqualToString:#"showDetail"])
{
NSIndexPath *indexPath = [[self.collectionView indexPathsForSelectedItems] lastObject];
DetailViewController *detailviewcontroller = [segue destinationViewController];
detailviewcontroller.photoArrayIndex = indexPath.row;
//photos array
detailviewcontroller.photosArray = _photoListArray;
}
Currently I am sending an array with the info of the photos and attempting to scroll to the position in the array.
I found this resource here for the horizontal paging:
http://adoptioncurve.net/archives/2013/04/creating-a-paged-photo-gallery-with-a-uicollectionview/
Which allows for paging using a collection view. I wrote that a detailViewController class.
Here's the question. How should I connect the two?
Idea 1: Have my mainView send an integer number representing the photo selected and the detailViewController will then load that one and begin lazy loading the photos.
Idea 2: Somehow preload some of the full screen photos and then send the integer with the spot in the array.
Idea 3: Send both the number and my array object over to the detailViewController so that I don't have to enumerate through the assets library again.
Are any of these the correct approach or did I miss the idea completely?
edit:
What I have in my detail controller is an uicollectionview flow layout with paging enabled.
This is the method where I set up the layout:
- (void) setCollectionView {
[self.collectionView registerClass:[DetailViewCell class] forCellWithReuseIdentifier:#"detailViewCell"];
//Flow Layout
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[flowLayout setMinimumInteritemSpacing:0.0f];
[flowLayout setMinimumLineSpacing:0.0f];
[self.collectionView setPagingEnabled:YES];
[self.collectionView setCollectionViewLayout:flowLayout];
CGFloat pageWidth = self.collectionView.frame.size.width;
NSInteger num = _photosArrayIndex + 1;
CGPoint scrollTo = CGPointMake(pageWidth * num, 0);
NSLog(#"scroll to: %#", NSStringFromCGPoint(scrollTo));
[self.collectionView setContentOffset:scrollTo];
}
What It should do is take the value from my main view and move to that image. Unfortunately it does not. I'm not sure why and also I feel like there is a better way of doing this. It just seems sort of Hackish.
How do I connect the two better controller better and what is the correct way of loading the photos/ how do I get to the photo (in the full size detail view) I was on when they were in a grid layout.
Help is appreciated.
OK, there are three parts to this.
First is the UICollectionViewController subclass to display the gallery of photos (UIImage).
Second is the UIPageViewController subclass to manage the swiping from side to side of each individual PhotoViewController.
Third is the UIViewController subclass (PhotoViewController) to display a single photo.
The storyboard will look something like this...
On the left is a UICollectionViewController this has a segue to the UIPageViewController in the middle. On the right is a UIViewController that has an Identifier set in the properties pane (note, there is no segue to this).
Identifier for the PhotoViewController...
In the PhotoPageViewController I have a custom object...
With a Class type PhotoPageModelController set in the properties pane... This is connected as the dataSource of the PhotoPageViewController.
That's pretty much all the storyboard set up required.
So, the first thing to set up is the PhotoPageModelController. This is the dataSource for the PhotoPageViewController as such will dispense subclasses of UIViewController so that the PhotoPageViewController can display them.
The Model Controller
PhotoPageModelController.h
#class PhotoViewController;
#interface PhotoPageModelController : NSObject <UIPageViewControllerDataSource>
// this is the array of the photos. Either an array of UIImages or objects containing
// them or something. My personal project had an array of photoIDs that I could use to
// pull the photos out of Core Data.
// In this example the array will contain instances of UIImage.
#property (nonatomic, strong) NSArray *photos;
- (PhotoViewController *)viewControllerAtIndex:(NSUInteger)index storyboard:(UIStoryboard *)storyboard;
- (NSUInteger)indexOfViewController:(PhotoViewController *)controller;
#end
PhotoPageModelController.m
#import "PhotoPageModelController.h"
#import "PhotoViewController.h"
#implementation PhotoPageModelController
- (UIImage *)photoAtIndex:(NSUInteger)index
{
// check that the index is in bounds and then return the UIImage to display.
// In my project I just returned the ID of the photo and let the photo
// controller load the actual image from core data. (See below)
if ([self.photos count] == 0
|| index >= [self.photos count]) {
return nil;
}
return self.photos[index];
}
#pragma mark - convenience methods
- (PhotoViewController *)viewControllerAtIndex:(NSUInteger)index storyboard:(UIStoryboard *)storyboard
{
UIImage *photo = [self photoAtIndex:index];
if (photo == nil) {
return nil;
}
// This is why we don't have a segue. We are loading it manually
// from the storyboard using the identifier.
EventPhotoViewController *controller = [storyboard instantiateViewControllerWithIdentifier:#"PhotoViewController"];
// The model controller is where the PhotoViewController gets the actual image from.
// Or an object containing the image with a name, date, details, etc...
// The controller doesn't know anything about the other photos. Only the one it's displaying.
controller.photo = photo;
return controller;
}
- (NSUInteger)indexOfViewController:(PhotoViewController *)controller
{
// Return the index of the given data view controller.
// For simplicity, this implementation uses a static array of model objects and the view controller stores the model object; you can therefore use the model object to identify the index.
return [self.photos indexOfObject:controller.photo];
}
#pragma mark - page view data source
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
// We need to find the index of the current controller so we can get the index
// and then the view controller for the one before it.
NSUInteger index = [self indexOfViewController:(PhotoViewController *) viewController];
if ((index == 0) || (index == NSNotFound)) {
// We have reached the beginning of the photos array so return nil.
// This tells the Page View Controller that there isn't another page.
return nil;
}
index--;
return [self viewControllerAtIndex:index storyboard:viewController.storyboard];
}
// This is the same as above but going forward instead of backward.
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger index = [self indexOfViewController:(EventPhotoViewController *) viewController];
if (index == NSNotFound) {
return nil;
}
index++;
if (index == [self.photoIDs count]) {
return nil;
}
return [self viewControllerAtIndex:index storyboard:viewController.storyboard];
}
#end
OK. So that is the Photo Page Model Controller.
The Page View Controller
Next for the PhotoPageViewController.
PhotoPageViewController.h
#import <Foundation/Foundation.h>
#interface PhotoPageViewController : UIPageViewController
#property (nonatomic, strong) NSArray *photos;
#property (nonatomic) NSUInteger initialIndex;
#end
PhotoPageViewController.m
#import "PhotoPageViewController.h"
#import "PhotoPageModelController.h"
#interface PhotoPageViewController ()
// this property is connected in the storyboard
#property (nonatomic, weak) IBOutlet PhotoPageModelController *modelController;
#end
#implementation PhotoPageViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.modelController.photos = self.photos;
// We use the initialIndex property to get the first controller and display it.
UIViewController *initialController = (UIViewController *)[self.modelController viewControllerAtIndex:self.initialIndex storyboard:self.storyboard];
[self setViewControllers:#[initialController]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:^(BOOL finished) {
}];
// That's it. Because we have the datasource class it makes this class really easy and short.
// It doesn't even need to know anything about the view controllers it is displaying.
// It's just a dispensing machine.
}
#end
The Photo View Controller
Next is the view controller that will display the actual photo.
All it needs is a property of type UIImage called photo and then a UIImageView to place it in. I'll leave this up to you as you can do it many different ways.
I've put a zoomable UIScrollView in mine so that the user can pinch zoom the photo. I've also got some extra info such as the name of the person who took the photo and the date it was taken etc... Set this up however you like.
The collection view segue
The final part (at last) is going from the collection view to the page view controller.
This is done in prepareForSegue.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"PhotoSegue"]) {
PhotoPageViewController *controller = segue.destinationViewController;
NSIndexPath *selectedIndex = [self.collectionView indexPathsForSelectedItems][0];
// The PageViewController doesn't need anything except the index to start on...
// i.e. the index of the photo that the user just selected.
controller.initialIndex = (NSUInteger)selectedIndex.item;
// ...and the array of photos it will be displaying.
controller.photos = self.photos;
// Everything else is done by the PageViewController.
}
}

Reading touch events in a QLPreviewController

I've got a QuickLook view that I view some of my app's documents in. It works fine, but I'm having my share of trouble closing the view again. How do I create a touch event / gesture recognizer for which I can detect when the user wants to close the view?
I tried the following, but no events seem to trigger when I test it.
/------------------------ [ TouchPreviewController.h ]---------------------------
#import <Quicklook/Quicklook.h>
#interface TouchPreviewController : QLPreviewController
#end
//------------------------ [ TouchPreviewController.m ]---------------------------
#import "TouchPreviewController.h"
#implementation TouchPreviewController
- (id)init:(CGRect)aRect {
if (self = [super init]) {
// We set it here directly for convenience
// As by default for a UIImageView it is set to NO
UITapGestureRecognizer *singleFingerDTap = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(handleSingleDoubleTap:)];
singleFingerDTap.numberOfTapsRequired = 2;
[self.view addGestureRecognizer:singleFingerDTap];
[self.view setUserInteractionEnabled:YES];
[self.view setMultipleTouchEnabled:YES];
//[singleFingerDTap release];
}
return self;
}
- (IBAction)handleSingleDoubleTap:(UIGestureRecognizer *) sender {
CGPoint tapPoint = [sender locationInView:sender.view.superview];
[UIView beginAnimations:nil context:NULL];
sender.view.center = tapPoint;
[UIView commitAnimations];
NSLog(#"TouchPreviewController tap!" ) ;
}
// I also tried adding this
- (BOOL)gestureRecognizer:(UIGestureRecognizer *) gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*) otherGestureRecognizer {
return YES;
}
#end
Edit: For clarification, this is how I instantiate the controller:
documents = [[NSArray alloc] initWithObjects: filename , nil ] ;
preview = [[TouchPreviewController alloc] init];
preview.dataSource = self;
preview.delegate = self;
//set the frame from the parent view
CGFloat w= backgroundViewHolder.frame.size.width;
CGFloat h= backgroundViewHolder.frame.size.height;
preview.view.frame = CGRectMake(0, 0,w, h);
//refresh the preview controller
[preview reloadData];
[[preview view] setNeedsLayout];
[[preview view] setNeedsDisplay];
[preview refreshCurrentPreviewItem];
//add it
[quickLookView addSubview:preview.view];
Also, I've defined the callback methods as this:
- (NSInteger) numberOfPreviewItemsInPreviewController: (QLPreviewController *) controller
{
return [documents count];
}
- (id <QLPreviewItem>) previewController: (QLPreviewController *) controller previewItemAtIndex: (NSInteger) index
{
return [NSURL fileURLWithPath:[documents objectAtIndex:index]];
}
Edit2: One thing i noticed. If I try making swiping gestures, I get the following message. This could shed some light on what is wrong/missing?
Ignoring call to [UIPanGestureRecognizer setTranslation:inView:] since
gesture recognizer is not active.
I think your example code is incomplete. It isn't clear how you are instantiating the TouchPreviewController (storyboard, nib file or loadView.)
I have never used the class so I could be way out in left field.
If you've already instantiated a UITapGestureRecognizer in the parent viewController, it is absorbing the tap events and they aren't passed on to your TouchPreviewController.
I would implement the view hierarchy differently by attaching the UITapGestureRecognizer to the parent viewController and handle presentation and unloading of the QLPreviewController there.
I think you might not have to subclass QLPreviewController by instantiating the viewController from a nib file.
When your parent viewController's UITapGestureRecognizer got an event you would either push the QLPreviewController on the navigation stack or pop it off the navigation stack when done.
Hope this is of some help.

How do I get NSTextFinder to show up

I have a mac cocoa app with a webview that contains some text. I would like to search through that text using the default find bar provided by NSTextFinder. As easy as this may seem reading through the NSTextFinder class reference, I cannot get the find bar to show up. What am I missing?
As a sidenote:
- Yes, I tried setting findBarContainer to a different view, same thing. I reverted back to the scroll view to eliminate complexity in debugging
- performTextFinderAction is called to perform the find operation
**App Delegate:**
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
self.textFinderController = [[NSTextFinder alloc] init];
self.webView = [[STEWebView alloc] initWithFrame:CGRectMake(0, 0, self.window.frame.size.width, 200)];
[[self.window contentView] addSubview:self.webView];
[self.textFinderController setClient:self.webView];
[self.textFinderController setFindBarContainer:self.webView.enclosingScrollView];
[[self.webView mainFrame] loadHTMLString:#"sample string" baseURL:NULL];
}
- (IBAction)performTextFinderAction:(id)sender {
[self.textFinderController performAction:[sender tag]];
}
**STEWebView**
#interface STEWebView : WebView <NSTextFinderClient>
#end
#implementation STEWebView
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect
{
// Drawing code here.
}
- (NSUInteger) stringLength {
return [[self stringByEvaluatingJavaScriptFromString:#"document.documentElement.textContent"] length];
}
- (NSString *)string {
return [self stringByEvaluatingJavaScriptFromString:#"document.documentElement.textContent"];
}
In my tests, WebView.enclosingScrollView was null.
// [self.textFinderController setFindBarContainer:self.webView.enclosingScrollView];
NSLog(#"%#", self.webView.enclosingScrollView);
Using the following category on NSView, it is possible to find the nested subview that extends NSScrollView, and set that as the container, allowing the NSTextFinder to display beautifully within a WebView
#interface NSView (ScrollView)
- (NSScrollView *) scrollView;
#end
#implementation NSView (ScrollView)
- (NSScrollView *) scrollView {
if ([self isKindOfClass:[NSScrollView class]]) {
return (NSScrollView *)self;
}
if ([self.subviews count] == 0) {
return nil;
}
for (NSView *subview in self.subviews) {
NSView *scrollView = [subview scrollView];
if (scrollView != nil) {
return (NSScrollView *)scrollView;
}
}
return nil;
}
#end
And in your applicationDidFinishLaunching:aNotification:
[self.textFinderController setFindBarContainer:[self scrollView]];
To get the Find Bar to appear (as opposed to the default Find Panel), you simply have to use the setUsesFindBar: method.
In your case, you'll want to do (in your applicationDidFinishLaunching:aNotification method):
[textFinderController setUsesFindBar:YES];
//Optionally, incremental searching is a nice feature
[textFinderController setIncrementalSearchingEnabled:YES];
Finally got this to show up.
First set your NSTextFinder instances' client to a class implementing the <NSTextFinderClient> protocol:
self.textFinder.client = self.textFinderController;
Next, make sure your NSTextFinder has a findBarContainer set to the webView category described by Michael Robinson, or get the scrollview within the webView yourself:
self.textFinder.findBarContainer = [self.webView scrollView];
Set the find bar position above the content (or wherever you wish):
[self.webView scrollView].findBarPosition = NSScrollViewFindBarPositionAboveContent;
Finally, tell it to show up:
[self.textFinder performAction:NSTextFinderActionShowFindInterface];
It should show up in your webView:
Also, not sure if it makes a difference, but I have the NSTextFinder in the XIB, with a referencing outlet:
#property (strong) IBOutlet NSTextFinder *textFinder;
You may also be able to get it by simply initing it like normal: self.textFinder = [[NSTextFinder alloc] init];

Keyboard Events Objective C

I'm having trouble receiving keyboard events within a subclass of NSView.
I can handle mouse events fine, but my keyDown and keyUp methods are never called. It was my understanding per the documentation that both types of events follow the same hierarchy, however this is seemingly not the case.
Is this a first responder issue? Some field somewhere grabbing the focus? I've tried overriding that but no luck.
Any insights would be greatly appreciated.
If you'd like to see.. this is within a custom NSView class:
#pragma mark -
#pragma mark I/O Events
-(void)keyDown:(NSEvent *)theEvent {
NSLog(#"Sup brah!");
}
-(void)keyUp:(NSEvent *)theEvent {
NSLog(#"HERE");
}
// This function works great:
-(void)mouseDown:(NSEvent *)theEvent {
NSNumber *yeah = [[NSNumber alloc] initWithBool:YES];
NSNumber *nah = [[NSNumber alloc] initWithBool:NO];
NSString *asf = [[NSString alloc] initWithFormat:#"%#", [qcView valueForOutputKey:#"Food_Out"]];
if ([asf isEqualToString:#"1"]) {
[qcView setValue:nah forInputKey:#"Food_In"];
best_food_x_loc = convertToQCX([[qcView valueForOutputKey:#"Food_1_X"] floatValue]);
best_food_y_loc = convertToQCY([[qcView valueForOutputKey:#"Food_1_Y"] floatValue]);
NSLog(#"X:%f, Y:%f",best_food_x_loc, best_food_y_loc);
} else {
[qcView setValue:yeah forInputKey:#"Food_In"];
}
}
You have to set your NSView to be first responder
- (BOOL)acceptsFirstResponder {
return YES;
}