Programmatically create NSWindow with specific size fails - objective-c

I'm trying to programmatically create a borderless NSWindow close to the mouse cursor and with the size of the image it should display. However I always get a much larger window (each side is about three times the size it should be)! I double-checked that my imageObj has the correct size and that all the NSSize and NSRect structures are created with correct values. The commented-out line doesn't work either (however which would be correct?)
I already searched through this site but I couldn't find any similar issue... What am I doing wrong?
Here is my code:
NSString* imageName = [[NSBundle mainBundle] pathForResource:#"os_unknown" ofType:#"icns"];
NSImage* imageObj = [[NSImage alloc] initWithContentsOfFile:imageName];
[view setImage:imageObj];
NSSize s = [imageObj size];
NSPoint p = [NSEvent mouseLocation];
NSRect r = [NSWindow frameRectForContentRect:NSMakeRect(p.x, p.y, s.width, s.height)
styleMask:NSBorderlessWindowMask];
//NSRect r = {p, s};
if (win) [win release];
win = [[NSWindow alloc] initWithContentRect:r
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:false];
[win setLevel:kCGUtilityWindowLevel];
[view setBounds:NSMakeRect(0, 0, s.width, s.height)];
[[win contentView] addSubview:view];
[win orderFront:sender];
Here *win is an NSWindow and *view is an NSImageView. Both are declared on top of my source file.
I'm running Snow Leopard so any strictly >10.6.8 code won't work (already tried something).
Thank you in advance for any help.

Solved! The NSImageView *view was created in Interface Builder. The size I got was the size set in there, no matter what code I used to resize it. By creating the NSImageView programmatically everything works great!
Special thanks to rdelmar who made me think and get the solution!

Related

Creating a NSTextView programmatically?

I'm can't seem to build a working NSTextView programmatically. Starting from a new project template I have this code (mostly coming from Apple's "Text System User Interface Layer Programming Guide"):
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSString *string = #"Here's to the ones who see things different.";
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithString:string];
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
[textStorage addLayoutManager:layoutManager];
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithContainerSize:NSMakeSize(300, 300)];
[layoutManager addTextContainer:textContainer];
NSTextView *textView = [[NSTextView alloc] initWithFrame:NSMakeRect(50, 50, 300, 300)
textContainer:textContainer];
[textContainer setWidthTracksTextView:YES];
[textView setVerticallyResizable:YES];
[textView setHorizontallyResizable:NO];
[textView setAutoresizingMask:NSViewWidthSizable];
[[self.window contentView] addSubview:textView];
}
Running the app, a window opens with a white square in it that's supposed to be the NSTextView, but there's no text, and there's no way to interact with the text view. Moreover, I tried adding text to the text view in code after the view is created using [textView setString:#"Some string."], but that doesn't work either. (Incidentally, I've also tried putting it in a NSScrollView first, in case that somehow was the issue, but that didn't help.)
I can't for the life of me figure out what the problem is. What am I missing?
This should work, although I tried it out myself and was unable to edit too. It could possibly be a bug now, but I'm not 100% sure. If you need to use the containers and layout managers just use the one that comes from the initWithFrame: method (without the text container).
NSTextView *textView = [[NSTextView alloc] initWithFrame:NSMakeRect(50, 50, 300, 300)];
NSLayoutManager *layoutManager = textView.layoutManager;
NSTextContainer *textContainer = textView.textContainer;
NSTextStorage *textStorage = textView.textStorage;
//Do your edits here
To expand on TheAmateurProgrammer's answer:
If you need to use the containers and layout managers just use the one that comes from the initWithFrame: method (without the text container)
With iOS, needed to create the text storage, layout manager, and text container for UITextView to work as intended. For NSTextView to function, needed to not create those. Had same results as OP until this change--the view was located accurately, but didn't display text or show insertion point or invoke delegate methods--and then the text view worked properly.

NSScrollView doesn't scroll

I'm porting an iPhone app that uses this tutorial into a Mac app. I've been able to get text to display in NSScrollView, but I can't get the text to scroll and I hope someone knows what I am missing.
In the iPhone app, CTView is subclassed from UIScrollView
CTView.h:
#interface CTView : UIScrollView <UIScrollViewDelegate> {
1) But there is no NSScrollViewDelegate in AppKit. Is the missing delegate interface to NSScrollView the problem?
So for the Mac app, CTView.h looks like the following:
#interface CTView : NSScrollView
In CTView.m I have
[self setHasHorizontalScroller:YES];
[self setAcceptsTouchEvents:YES];
Also inside CTView.m I create a NSMutableArray of frames as
self.frames = [NSMutableArray array];
and fill the array up with frames. I also set the frame for the document view for the complete larger image that I want to be able to scroll through as:
[[self contentView] setFrame:[self bounds]];
[self.documentView setFrame: NSMakeRect(0, 0, totalPages * self.bounds.size.width, textFrame.size.height)];
The first frame is visible in the CTView, but when I move the horizontal scroll bar, the second frame doesn't show up in CTView.
I'm using Xcode 4.3.3 and Mac OS X 10.7.4.
Does anyone know what I need to do differently from UIScrollView for NSScrollView to be able to scroll through the frames?
Finally figured it out. Whew!
1) NSScrollView needs a view for its documentView, where the documentView is what is scrolled over. So in the nib I created a NSScrollView that contained a view for the documentView and set the documentView to that view as shown by the code in CTView.m
NSArray *viewArray = [self subviews];
NSArray *docViewArray = [[viewArray objectAtIndex:0] subviews];
NSView *docView = [docViewArray objectAtIndex:0];
[self setDocumentView:docView];
2) Then I added the array of frames, that would normally be added to UIScrollView, to the documentView of NSScrollView. The array of frames consists of multiple elements of content.
while (textPos < [attString length]) {
CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(textPos, 0), innerPath, NULL);
CFRange frameRange = CTFrameGetVisibleStringRange(frame);
CTColumnView* content = [[[CTColumnView alloc] initWithFrame: NSMakeRect(0, 0, self.contentSize.width, self.contentSize.height)] autorelease];
[docView addSubview: content]; // <<-- Here is where the frames are added to the documentView
textPos += frameRange.length;
}
And that did the trick.

Changing Popover view frame on fly

When a popover is displaying how can I make its size variable depending on condition check? Is this functionality supported or not when working with a popover?
Here is my sample for changing frame size:
CGFloat newHeight = 200;
NSRect newFrame = [parentView frame];
newFrame.size.height = newHeight;
NSView* childView = someView;
[parentView setFrame:newFrame];
[self.view addSubview:childView];
Don't know if anything was changed but in 10.9 all you have to do is setContentSize on the popover, e.g.:
[popoverView setFrame:NSMakeRect(0, 0, 581, 581)];
[thePopover setContentSize:popoverView.frame.size];
You need to change the popupwindow.contentViewController property of the NSPopover to a new NSViewController with a different-sized view.
That is, resizing the view's frame will only result in weird drawing problems. To get the popover window to change size, the contentViewController must be changed.
Ideally, you would set up a new view controller which is essentially a copy of your existing NSViewController, but containing a view that is taller/shorter. But in the worst-case scenario, you can do something like this:
gPopoverWindow.contentViewController = [[[NSViewController alloc] initWithNibName: #"tempNibName" bundle: nil] autorelease];
NSView *v = self.view;
NSRect b = [v frame];
b.size.height += 25;
[v setFrame: b];
gPopoverWindow.contentViewController = self;
In my testing, this resulted in the popover beginning a shrink animation (because of being set to the temp view controller), then growing to its new size.

applicationMusicPlayer volume notification

I am using an applicationMusicPlayer and when i try to change the volume appear the visual notification, as shown in the picture.
Here the code I am using:
[MPMusicPlayerController applicationMusicPlayer] setVolume:newVolune];
Anyone knows how to hide this notification?
I don't know where the docs says so, but if you add a MPVolumeView view to your app the system volume overlay goes away. Even if it is not visible:
- (void) viewDidLoad
{
[super viewDidLoad];
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame: CGRectZero];
[self.view addSubview: volumeView];
[volumeView release];
...
}
You can use the hardware volume buttons, the setVolume method or directly interact with the control (if visible) that the overlay doesn't show up.
For iOS6 I had to set an image with alpha 0 and non-zero size to the MPVolumeView's image fields in order to get the default volume change notification to disappear.
// hide the hardware volume slider
UIImage *thumb = [[UIImage alloc] initWithCIImage:[UIImage imageNamed:#"volumeHider"].CIImage scale:0.0 orientation:UIImageOrientationUp];
MPVolumeView *hwVolume = [[MPVolumeView alloc] initWithFrame:self.frame];
[hwVolume setUserInteractionEnabled:NO];
hwVolume.showsRouteButton = NO;
[hwVolume setVolumeThumbImage:thumb forState:UIControlStateNormal];
[hwVolume setMinimumVolumeSliderImage:thumb forState:UIControlStateNormal];
[hwVolume setMaximumVolumeSliderImage:thumb forState:UIControlStateNormal];
[self addSubview:hwVolume];
This made the MPVolumeView be "visible" on the screen, but invisible to the user.
I encountered the same issue recently. Instead of adding the MPVolumeView to current view controller's view, I add it to the application's window once at the start of the app:
CGRect rect = CGRectMake(-500, -500, 0, 0);
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:rect];
[self.window addSubview:volumeView];
This works in both iOS 7 and 8.
Swift 3
You can hide the System MPVolumeView using
override func viewDidLoad() {
super.viewDidLoad()
let volumeView = MPVolumeView(frame: CGRect.zero)
self.view.addSubview(volumeView)
}
I had success with this in iOS 6. Although it wouldn't perform well. It caused quite a bit of lag when sliding the thumbImage. I did have to take out the last 2 lines of code in order for this to work.
[volumeView release];
...
For me, on iOS 7, none of above solutions worked. Here is how I did it:
_volume = [[MPVolumeView alloc] initWithFrame: CGRectMake(-100,-100,16,16)];
_volume.showsRouteButton = NO;
_volume.userInteractionEnabled = NO;
[self.view addSubview:_volume];
[_volume release];
That is, simply set MPVolumeView's frame to an off-screen location such as (-100,-100).

Cocoa - Animate a NSWindow with setFrame

I have the following block of code.
NSRect windowFrame = [window frame];
windowFrame.size.height = [view frame].size.height + WINDOW_TOOLBAR_HEIGHT;
windowFrame.size.width = [view frame].size.width;
windowFrame.origin.y = NSMaxY([window frame]) - ([view frame].size.height + WINDOW_TOOLBAR_HEIGHT);
if ([[contentView subviews] count] != 0)
{
[[[contentView subviews] objectAtIndex:0] removeFromSuperview];
}
[window setFrame:windowFrame display:YES animate:YES];
[contentView setFrame:[view frame]];
[contentView addSubview:view];
It switches the frame to the new view but I never get a shrinking/growing animation. If I place this before the [window]
NSLog([NSString stringWithFormat: #"%.2f", windowFrame.size.height]);
I get different sizes.. here is the output
2011-09-07 14:13:02.418 Spark[29919:903] 492.00
2011-09-07 14:13:03.610 Spark[29919:903] 580.00
2011-09-07 14:13:05.955 Spark[29919:903] 492.00
2011-09-07 14:13:08.339 Spark[29919:903] 255.00
Not sure what I am missing.
thanks!
EDIT
I've added a simple project to see my issues
http://dl.dropbox.com/u/13731121/Spark.zip
I've reviewed your project and here are my points:
Your preference.xib is... non standard to say the least. Usually when creating window controller, you should set window controller class as window nib's file owner. Your preference.xib file owner is NSObject while PreferenceController is separate object. So I've fixed that and rebound almost all IBOutlets.
I've rebound almost all outlets because you don't need such thing as contentView, because window itself has such property as contentView, hence it's enough to set the contentView property of the window.
You set contentView's FRAME which is very, very wrong (unless you really know what you're doing). I've changed it to set contentView's BOUNDS instead.