Unable to get tab order working within NSPopover - macos

I have a View within an NSPopover, and I am unable to set the tab order correctly. I have set the nextKeyView within my 4 text fields. But it tends to flip from TextField1 to Search1, instead of TextField1 -> TextField2. I have tried inserting [self.view.window makeFirstResponder:textField1] also [self.view.window setInitialFirstResponder:textField1] along with recalculatekeyviewloop but with no luck.
Any help would be much appreciated.

I had a similiar problem when composing the popover-view of certain subviews programatically in awakeFromNIB. I could solve the problem by inserting the subviews after the popover had its private NSPopoverWindow set (i.e. it was shown the first time). It seems like the popover is re-evaluating the view-loop when the popover-view is embedded in the private child-window - ignoring the view-loop given in the view.
You could try the following:
-(void) popoverDidShow:(NSNotification *)notification{ // NSPopoverDelegate-method
if (!popoverDidShowForTheFirstTime){
[self setUpViews];
}...
-(void) setUpViews{
popoverDidShowForTheFirstTime = YES;
// insert views and establish nextKeyViews ...

Related

How to expand table view cell and show content beneath it?

I want to have the table view cell expand and show the buttons that I have laid out below the visible view when the cell isn't selected. So far I have managed to expand the cell so that the entire view shows with the buttons, but there is one major problem with this....
The buttons that are supposed to be revealed only when the cell is selected always appear in the table, and the table view looks really weird becuase for each cell there are buttons overlapping the next cell which were supposed to be hidden!
I have tired making a subclass of the cell, but I am stuck because when I override the setSelected method to show the button, all the buttons from all the cells show up, not just the one I clicked, Ill provide my code below.
I there an easier way to show the buttons without using a subclass? And if not how could I use the subclass in a way that wouldn't show all the buttons for all the cells?
Cell Subclass (.m file)
- (void)awakeFromNib {
// Initialization code
editHidden.hidden = YES;
removeHidden.hidden = YES;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
editHidden.hidden = NO;
removeHidden.hidden = NO;
// Configure the view for the selected state
}
Your table view delegate needs to implement tableView:heightForRowAtIndexPath:. Implement this method to return the correct height for your cell given the state that it is in (collapsed or expanded). When it comes time to expand your cell you should update your state and call [tableView beginUpdates]; [tableView endUpdates]; to have it recalculate and relayout the tableview.

Change NSTextField's behavior for multiple clicks in a row

I have a NSTextField which is nested by a custom view and I want to change the default behavior of multiple clicks in a row (double click, tripple click etc.), similarly to the behavior of text nodes MindNode (see the image below).
I want the first click to "activate" the text field and then go on from the beginning (like reseting the click count of the event).
I have following ideas, but I don't know how to implement them and if they actually make sense:
Somehow change the time using +[NSEvent doubleClickInterval] and slow down the second click.
Reduce the click count programmatically?
Make the NSTextField non-selectable using -hitTest:, forward the click to the superview, change some parameter of the text field and accept the next clicks. In this case, the click count of the second click is still 2.
Override -mouseDown: and not call super. This breaks the NSTextField's selection functionality.
I hope there is an easier way to achieve this, which I have overlooked.
Thanks for your answers!
Here is a graphical representation of the problem:
I would do this by embedding the text field and a custom view in an NSBox, which would be set to the custom type, initially with no background color or border (so it would be invisible). Initially, the custom view would be on top and it would have a mouseDown: method that would receive the first click. In that method you could rearrange the box's subviews so that the text field would then be on top and receive the next clicks. If you wanted, the box could be somewhat bigger than the text field so you could give it a background color or other drawing that would look like a custom activation ring around the text field. In the text field's controlTextDidEndEditing: method, you could reset the system back to the beginning state, so it would be ready for the next time you click on it.
After Edit: Here is the code I'm using in my overlay class:
#implementation Overlay
static NSComparisonResult rdComparator( NSView *view1, NSView *view2, void *context ) {
if ([view1 isKindOfClass:[NSTextField class]])
return NSOrderedDescending;
else if ([view2 isKindOfClass:[NSTextField class]])
return NSOrderedAscending;
return NSOrderedSame;
}
-(void)mouseDown:(NSEvent *)theEvent {
self.box.fillColor = [NSColor redColor];
NSView *contentView = self.box.subviews.lastObject;
[contentView sortSubviewsUsingFunction:rdComparator context:nil];
}
I've solved it by subclassing NSTextField and decrementing click count of mouse down events programmatically. Using a boolean property of the subclass I am able to turn this special behavior on and off.
- (void)mouseDown:(NSEvent *)theEvent
{
if (self.specialBehavior) {
theEvent = [NSEvent mouseEventWithType:theEvent.type
location:theEvent.locationInWindow
modifierFlags:theEvent.modifierFlags
timestamp:theEvent.timestamp
windowNumber:theEvent.windowNumber
context:theEvent.context
eventNumber:theEvent.eventNumber
clickCount:theEvent.clickCount - 1
pressure:theEvent.pressure];
}
[super mouseDown:theEvent];
}
To simplify this long method call, I wrote a category method for NSEvent which decrements the click count of an event.

NSTableView rowViewAtRow: always returning nil

I'm trying to display an NSPopover with additional information to a selected row of an NSTableView. For that I need to get a reference to the view representation of the selected row so I can "attach" my popover to it:
NSInteger row = [[self membersTableView] selectedRow];
NSTableRowView *aView = [[self membersTableView] rowViewAtRow: row makeIfNecessary: YES];
[self setQuickLookPopoverController: [QuickLookPopoverController showPopoverFor: anObject at: aView]];
In the above, the result of aView is always nil. According to Apple documentation, this is the method to obtain a view object, given a selected row. Especially the last sentence of the discussion is a bit weird:
Discussion This method will first attempt to return a currently
displayed view in the visible area. If there is no visible view, and
makeIfNecessary is YES, a prepared temporary view is returned. If
makeIfNecessary is NO, and the view is not visible, nil will be
returned.
In general, makeIfNecessary should be YES if you require a resulting
view, and NO if you only want to update properties on a view only if
it is available (generally this means it is visible).
An exception will be thrown if row is not within the numberOfRows. The
returned result should generally not be held onto for longer than the
current run loop cycle. It is better to call
rowViewAtRow:makeIfNecessary: whenever a view is required..
Why is this method always returning nil?
Solved it. I used NSTableView's method (NSRect) rectOfRow: (NSInteger) rowIndex which will give the frame of the required row.
Thanks for showing me the right direction, I had the same problem! I ended up doing the following, but note that I disabled selection of empty rows and that the following code is inside an IBAction:
[popOver showRelativeToRect:[sender bounds]
ofView:[sender rowViewAtRow:[sender selectedRow]
makeIfNecessary:YES]
preferredEdge:NSMaxXEdge];

Can't get subview animation to appear even after alloc :)

I have a subview loaded into an UIView. In the subview's .m file I have the following:
- (void)startAnimation {
// Array to hold png images
imageArray = [[NSMutableArray alloc] initWithCapacity:22];
animatedImages = [[UIImageView alloc] initWithImage:viewForImage];
// Build array of images, cycling through image names
for (int i = 1; i < 22; i++){
[imageArray addObject:[UIImage imageNamed:[NSString stringWithFormat:#"image%d.png", i]]];
}
animatedImages.animationImages = [NSArray arrayWithArray:imageArray];
// One cycle through all the images takes 1 seconds
animatedImages.animationDuration = 2.0;
// Repeat forever
animatedImages.animationRepeatCount = 0;
// Add subview and make window visible
[viewForMovie addSubview:animatedImages];
// Start it up
animatedImages.startAnimating;
NSLog(#"Executed");
}
Please be noted that I have in the .h file:
UIImageView *animatedImages;
NSMutableArray *imageArray;
UIView *viewForMovie;
#property(nonatomic,retain)IBOutlet UIView *viewForMovie;
and in the .m file:
#synthesize viewForMovie;
and I have connected viewForMovie to a UIView in IB. I've been on this for several hours now and have tried many variations I've found on the web but cannot get it to work. There are no errors and the other GUI graphics in the subview appear very nicely....but the animation just doesn't appear over top where it should. Also the NSlog reports that the method has in fact been called from the parent. Can anyone see any blaring issues? Thx.
PS: I'm pretty new at this.
Based on the code shown and the behavior you see so far, here are my suggestions:
Make sure the viewForMovie IBOutlet is connected properly in Interface Builder. If it's not connected properly (and so nil), nothing will appear. If you didn't mean to make it an IBOutlet in the first place, then you'll need to manually create it and add it as a subview to self before using it.
Not sure why you have the viewForMovie UIView in the first place. Is this subview's class (let's call it MySubview) a subclass of UIView? You can just show the animation in self instead of adding another subview inside it. Are you going to add more uiviews to this subview besides the viewForMovie?
To get rid of the "may not respond to" warning, declare the startAnimation method in the MySubview.h file (under the #property line):
-(void)startAnimation;
The fact that the warning says "UIView may not respond" also tells you that the parent view has declared newView as a UIView instead of MySubview (or whatever you've named the subview class). Change the declaration in the parent from UIView *newView; to MySubview *newView;.
In the initWithImage, what is "viewForImage"? Is it a UIImage variable or something else?
If all of the images are the same size and fit in the subview as-is, you don't need to set the frame--the initWithImage will automatically size the UIImageView using the init-image dimensions.
Double check that the images you are referencing in the for-loop are named exactly as they are in the code and that they have actually been added to the project.
Finally, you should release the objects you alloc in startAnimation. At the end of the method, add:
[imageArray release];
[animatedImages release];
The only item, however, that I think is actually preventing the animation from appearing right now is item 1.

Dynamic Results and Covering Data

Today I have a question that sprouted off of this one: Database Results in Cocoa. It's regarding using the data that was returned by a database to create a certain number of questions. I am using a form of the following code (this was posted in the question).
NSMutableDictionary * interfaceElements = [[NSMutableDictionary alloc] init];
for (NSInteger i = 0; i < numberOfTextFields; ++i) {
//this is just to make a frame that's indented 10px
//and has 10px between it and the previous NSTextField (or window edge)
NSRect frame = NSMakeRect(10, (i*22 + (i+1)*10), 100, 22);
NSTextField * newField = [[NSTextField alloc] initWithFrame:frame];
//configure newField appropriately
[[myWindow contentView] addSubview:newField];
[interfaceElements setObject:newField forKey:#"someUniqueIdentifier"];
[newField release];
}
However, now when I attempt to use IFVerticallyExpandingTextfield (from http://www.cocoadev.com/index.pl?IFVerticallyExpandingTextField), or create any large amount of text, it simply goes over the other drawn content. I looked into using setAutosizingMask: on the object, but it has not worked so far.
Thanks for any help.
EDIT: What I want the effect to look like is called "Correct TextField" and what happens is called "StackOverflow Sample" - http://www.mediafire.com/?sharekey=bd476ea483deded875a4fc82078ae6c8e04e75f6e8ebb871.
EDIT 2: And if no one knows how to use this IFVerticallyExpandingTextfield class, would anyone know if there is another way to accomplish the effect?
Do you mean this?
http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaDrawingGuide/GraphicsContexts/GraphicsContexts.html
Your question is not very clear to me but this might help ^^^.
Look at 'Modifying the Current Graphics State' on that page.
What about just exactly copying the code from the 'Correct textfield' example and use it in your application? Or start your application from the 'Correct texfield' example.
Also
A comment on http://www.cocoadev.com/index.pl?IFVerticallyExpandingTextField says:
Give it a try! You should be able to
throw this into a project, read the
files in Interface Builder, and use
the custom class pane to make an
NSTextField into an
IFVerticallyExpandingTextField. You'll
need to set the layout and
linebreaking attributes for word
wrapping for this to work.
Although expansion should work
properly when the textfield is
embedded in a subview, I'm having some
trouble dealing with NSScrollViews.
The field expands into the
scrollview's content view, but none of
the controls on the scrollbar appear.
Some help here would be appreciated.

Resources