2013-04-21 13:45:20 +00:00
|
|
|
/*
|
|
|
|
NSPopover.m
|
|
|
|
|
|
|
|
The popover class
|
|
|
|
|
|
|
|
Copyright (C) 2013 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
Author: Gregory Casamento <greg.casamento@gmail.com>
|
|
|
|
Date: 2013
|
|
|
|
|
|
|
|
This file is part of the GNUstep GUI Library.
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
License along with this library; see the file COPYING.LIB.
|
2023-10-01 11:47:05 +00:00
|
|
|
If not, see <http://www.gnu.org/licenses/> or write to the
|
|
|
|
Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
2013-04-21 13:45:20 +00:00
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
2013-04-21 21:32:36 +00:00
|
|
|
#import <Foundation/NSArchiver.h>
|
|
|
|
#import <Foundation/NSKeyedArchiver.h>
|
|
|
|
#import <Foundation/NSNotification.h>
|
|
|
|
|
|
|
|
#import "AppKit/NSPopover.h"
|
|
|
|
#import "AppKit/NSViewController.h"
|
|
|
|
#import "AppKit/NSView.h"
|
2021-10-02 21:28:24 +00:00
|
|
|
#import "AppKit/NSPanel.h"
|
2021-09-30 07:36:35 +00:00
|
|
|
#import "AppKit/NSNibLoading.h"
|
|
|
|
#import "AppKit/NSStoryboard.h"
|
2021-10-02 21:28:24 +00:00
|
|
|
#import "AppKit/NSGraphics.h"
|
2013-04-21 21:32:36 +00:00
|
|
|
|
2021-10-02 21:28:24 +00:00
|
|
|
// Popover private classes
|
2021-09-30 07:36:35 +00:00
|
|
|
|
2021-10-02 21:28:24 +00:00
|
|
|
@interface GSPopoverView : NSView
|
2021-09-30 07:36:35 +00:00
|
|
|
@end
|
|
|
|
|
2021-10-02 21:28:24 +00:00
|
|
|
@implementation GSPopoverView
|
|
|
|
|
|
|
|
- (instancetype) initWithFrame: (NSRect)frame
|
|
|
|
{
|
|
|
|
self = [super initWithFrame: frame];
|
|
|
|
if (self)
|
|
|
|
{
|
|
|
|
[self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) drawRect: (NSRect)dirtyRect
|
|
|
|
{
|
|
|
|
NSRectEdge sides[] = {NSMinXEdge, NSMaxYEdge, NSMaxXEdge, NSMinYEdge};
|
|
|
|
NSColor *black = [NSColor blackColor];
|
|
|
|
NSColor *white = [NSColor whiteColor];
|
|
|
|
NSColor *colors[] = {white, white, black, black};
|
|
|
|
NSRect bounds = [self bounds];
|
|
|
|
|
|
|
|
[super drawRect: dirtyRect];
|
|
|
|
NSDrawColorTiledRects(bounds, bounds, sides, colors, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
@interface GSPopoverPanel : NSPanel
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation GSPopoverPanel
|
|
|
|
|
|
|
|
- (id) initWithContentRect: (NSRect)contentRect
|
2023-10-01 11:47:05 +00:00
|
|
|
styleMask: (NSUInteger)aStyle
|
|
|
|
backing: (NSBackingStoreType)bufferingType
|
|
|
|
defer: (BOOL)flag
|
2021-10-02 21:28:24 +00:00
|
|
|
{
|
|
|
|
self = [super initWithContentRect: contentRect
|
2023-10-01 11:47:05 +00:00
|
|
|
styleMask: aStyle
|
|
|
|
backing: bufferingType
|
|
|
|
defer: flag];
|
2021-10-02 21:28:24 +00:00
|
|
|
if (self)
|
|
|
|
{
|
2021-10-03 09:15:16 +00:00
|
|
|
[super setContentView: AUTORELEASE([[GSPopoverView alloc]
|
2023-10-01 11:47:05 +00:00
|
|
|
initWithFrame: contentRect])];
|
2023-10-08 10:23:26 +00:00
|
|
|
[self setReleasedWhenClosed: YES];
|
2021-10-02 21:28:24 +00:00
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) orderOut: (id)sender
|
|
|
|
{
|
|
|
|
[super orderOut: sender];
|
|
|
|
[self close];
|
|
|
|
}
|
|
|
|
|
2023-10-01 11:47:05 +00:00
|
|
|
- (BOOL) canBecomeKeyWindow
|
2021-10-02 21:28:24 +00:00
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
2023-10-01 11:47:05 +00:00
|
|
|
- (BOOL) canBecomeMainWindow
|
2021-10-02 21:28:24 +00:00
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setContentView: (NSView *)view
|
|
|
|
{
|
|
|
|
[[super contentView] addSubview: view];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSView *) contentView
|
|
|
|
{
|
|
|
|
NSArray *subviews = [[super contentView] subviews];
|
|
|
|
|
|
|
|
if ([subviews count] == 0)
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
2023-10-01 11:47:05 +00:00
|
|
|
|
2021-10-02 21:28:24 +00:00
|
|
|
return [subviews objectAtIndex: 0];
|
|
|
|
}
|
|
|
|
|
2021-09-30 07:36:35 +00:00
|
|
|
@end
|
2013-04-21 13:45:20 +00:00
|
|
|
|
|
|
|
/* Class */
|
|
|
|
@implementation NSPopover
|
|
|
|
|
|
|
|
/* Properties */
|
2021-10-02 21:28:24 +00:00
|
|
|
|
2013-04-21 21:32:36 +00:00
|
|
|
- (void) setAnimates: (BOOL)flag
|
2013-04-21 13:45:20 +00:00
|
|
|
{
|
|
|
|
_animates = flag;
|
|
|
|
}
|
|
|
|
|
2013-04-21 21:32:36 +00:00
|
|
|
- (BOOL) animates
|
2013-04-21 13:45:20 +00:00
|
|
|
{
|
|
|
|
return _animates;
|
|
|
|
}
|
|
|
|
|
2013-04-21 21:32:36 +00:00
|
|
|
- (void) setAppearance: (NSPopoverAppearance)value
|
2013-04-21 13:45:20 +00:00
|
|
|
{
|
|
|
|
_appearance = value;
|
|
|
|
}
|
|
|
|
|
2013-04-21 21:32:36 +00:00
|
|
|
- (NSPopoverAppearance) appearance
|
2013-04-21 13:45:20 +00:00
|
|
|
{
|
|
|
|
return _appearance;
|
|
|
|
}
|
|
|
|
|
2013-04-21 21:32:36 +00:00
|
|
|
- (void) setBehavior: (NSPopoverBehavior)value
|
2013-04-21 13:45:20 +00:00
|
|
|
{
|
|
|
|
_behavior = value;
|
|
|
|
}
|
|
|
|
|
2013-04-21 21:32:36 +00:00
|
|
|
- (NSPopoverBehavior) behavior
|
2013-04-21 13:45:20 +00:00
|
|
|
{
|
|
|
|
return _behavior;
|
|
|
|
}
|
|
|
|
|
2013-04-21 21:32:36 +00:00
|
|
|
- (void) setContentSize: (NSSize)value
|
2013-04-21 13:45:20 +00:00
|
|
|
{
|
|
|
|
_contentSize = value;
|
|
|
|
}
|
|
|
|
|
2013-04-21 21:32:36 +00:00
|
|
|
- (NSSize) contentSize
|
2013-04-21 13:45:20 +00:00
|
|
|
{
|
|
|
|
return _contentSize;
|
|
|
|
}
|
|
|
|
|
2013-04-21 21:32:36 +00:00
|
|
|
- (void) setContentViewController: (NSViewController *)controller
|
2013-04-21 13:45:20 +00:00
|
|
|
{
|
2021-09-30 07:36:35 +00:00
|
|
|
if ([NSStoryboard mainStoryboard] == nil)
|
|
|
|
{
|
|
|
|
NSString *controllerClassName = NSStringFromClass([controller class]);
|
|
|
|
BOOL loaded = [NSBundle loadNibNamed: controllerClassName
|
|
|
|
owner: controller];
|
|
|
|
if (!loaded)
|
2023-10-01 11:47:05 +00:00
|
|
|
{
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
format: @"Could not load controller %@", controllerClassName];
|
|
|
|
}
|
2021-09-30 07:36:35 +00:00
|
|
|
else
|
2023-10-01 11:47:05 +00:00
|
|
|
{
|
|
|
|
if ([controller view] == nil)
|
|
|
|
{
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
format: @"Loaded controller named %@, but view is not set", controllerClassName];
|
|
|
|
}
|
|
|
|
}
|
2021-09-30 07:36:35 +00:00
|
|
|
}
|
2013-04-21 21:32:36 +00:00
|
|
|
ASSIGN(_contentViewController, controller);
|
2013-04-21 13:45:20 +00:00
|
|
|
}
|
|
|
|
|
2013-04-21 21:32:36 +00:00
|
|
|
- (NSViewController *) contentViewController
|
2013-04-21 13:45:20 +00:00
|
|
|
{
|
|
|
|
return _contentViewController;
|
|
|
|
}
|
|
|
|
|
2013-04-24 09:25:56 +00:00
|
|
|
- (void) setDelegate: (id)value
|
2013-04-21 13:45:20 +00:00
|
|
|
{
|
|
|
|
_delegate = value;
|
|
|
|
}
|
|
|
|
|
2013-04-24 09:25:56 +00:00
|
|
|
- (id) delegate
|
2013-04-21 13:45:20 +00:00
|
|
|
{
|
|
|
|
return _delegate;
|
|
|
|
}
|
|
|
|
|
2013-04-21 21:32:36 +00:00
|
|
|
- (void) setPositioningRect: (NSRect)value
|
2013-04-21 13:45:20 +00:00
|
|
|
{
|
|
|
|
_positioningRect = value;
|
|
|
|
}
|
|
|
|
|
2013-04-21 21:32:36 +00:00
|
|
|
- (NSRect) positioningRect
|
2013-04-21 13:45:20 +00:00
|
|
|
{
|
|
|
|
return _positioningRect;
|
|
|
|
}
|
|
|
|
|
2013-04-21 21:32:36 +00:00
|
|
|
- (BOOL) isShown
|
2013-04-21 13:45:20 +00:00
|
|
|
{
|
|
|
|
return _shown;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Methods */
|
2021-10-02 21:28:24 +00:00
|
|
|
|
2013-04-21 21:32:36 +00:00
|
|
|
- (void) close
|
2013-04-21 13:45:20 +00:00
|
|
|
{
|
2021-10-02 21:28:24 +00:00
|
|
|
[_realPanel close];
|
2023-10-01 10:56:53 +00:00
|
|
|
_shown = NO;
|
2013-04-21 13:45:20 +00:00
|
|
|
}
|
|
|
|
|
2013-04-21 21:32:36 +00:00
|
|
|
- (IBAction) performClose: (id)sender
|
2013-04-21 13:45:20 +00:00
|
|
|
{
|
2023-10-01 10:56:53 +00:00
|
|
|
[_realPanel performClose: sender];
|
|
|
|
_shown = NO;
|
2013-04-21 13:45:20 +00:00
|
|
|
}
|
|
|
|
|
2013-04-21 21:32:36 +00:00
|
|
|
- (void) showRelativeToRect: (NSRect)positioningRect
|
2023-10-01 11:47:05 +00:00
|
|
|
ofView: (NSView *)positioningView
|
|
|
|
preferredEdge: (NSRectEdge)preferredEdge
|
2013-04-21 13:45:20 +00:00
|
|
|
{
|
2013-04-24 09:25:56 +00:00
|
|
|
NSView *view = nil;
|
|
|
|
NSRect screenRect;
|
|
|
|
NSRect windowFrame;
|
|
|
|
NSRect viewFrame;
|
2023-10-01 11:47:05 +00:00
|
|
|
|
2013-04-24 09:25:56 +00:00
|
|
|
[_contentViewController loadView];
|
|
|
|
view = [_contentViewController view];
|
|
|
|
viewFrame = [view frame];
|
|
|
|
|
2021-10-02 21:28:24 +00:00
|
|
|
if (!_realPanel)
|
2021-09-30 07:36:35 +00:00
|
|
|
{
|
2021-10-02 21:28:24 +00:00
|
|
|
_realPanel = [[GSPopoverPanel alloc] initWithContentRect: viewFrame
|
|
|
|
styleMask: NSBorderlessWindowMask
|
|
|
|
backing: NSBackingStoreRetained
|
|
|
|
defer: NO];
|
2023-10-01 11:47:05 +00:00
|
|
|
|
2021-10-02 21:28:24 +00:00
|
|
|
[_realPanel setBackgroundColor: [NSColor darkGrayColor]];
|
|
|
|
[_realPanel setReleasedWhenClosed: YES];
|
|
|
|
[_realPanel setExcludedFromWindowsMenu: YES];
|
|
|
|
[_realPanel setLevel: NSPopUpMenuWindowLevel];
|
|
|
|
[_realPanel setAutodisplay: NO];
|
|
|
|
[_realPanel setDelegate: self];
|
|
|
|
[_realPanel setContentView: view];
|
2021-09-30 07:36:35 +00:00
|
|
|
}
|
2023-10-01 11:47:05 +00:00
|
|
|
|
2013-04-24 09:25:56 +00:00
|
|
|
screenRect = [[positioningView window] convertRectToScreen:positioningRect];
|
2021-10-02 21:28:24 +00:00
|
|
|
windowFrame = [_realPanel frame];
|
2013-04-24 09:25:56 +00:00
|
|
|
windowFrame.origin = screenRect.origin;
|
|
|
|
|
|
|
|
if(NSMinXEdge == preferredEdge)
|
|
|
|
{
|
|
|
|
windowFrame.origin.y -= viewFrame.size.height;
|
|
|
|
}
|
|
|
|
else if(NSMaxXEdge == preferredEdge)
|
|
|
|
{
|
|
|
|
windowFrame.origin.y += viewFrame.size.height;
|
|
|
|
}
|
|
|
|
else if(NSMinYEdge == preferredEdge)
|
|
|
|
{
|
|
|
|
windowFrame.origin.x -= viewFrame.size.width;
|
|
|
|
}
|
|
|
|
else if(NSMaxYEdge == preferredEdge)
|
|
|
|
{
|
|
|
|
windowFrame.origin.x += viewFrame.size.width;
|
|
|
|
}
|
|
|
|
|
2021-10-02 21:28:24 +00:00
|
|
|
[_realPanel setFrame: windowFrame display: YES];
|
|
|
|
[_realPanel makeKeyAndOrderFront:self];
|
2023-10-01 11:47:05 +00:00
|
|
|
|
2021-10-02 21:28:24 +00:00
|
|
|
NSDebugLog(@"Showing relative to in window %@",NSStringFromRect(positioningRect));
|
|
|
|
NSDebugLog(@"Showing relative to in screen %@",NSStringFromRect(screenRect));
|
2023-10-01 11:47:05 +00:00
|
|
|
|
2021-10-02 21:28:24 +00:00
|
|
|
_shown = YES;
|
2013-04-24 09:25:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) windowShouldClose: (id)sender
|
|
|
|
{
|
|
|
|
return [_delegate popoverShouldClose:self];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) windowDidClose: (NSNotification *)notification
|
|
|
|
{
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:NSPopoverDidCloseNotification
|
|
|
|
object:self
|
|
|
|
userInfo:nil];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) windowWillClose: (NSNotification *)notification
|
|
|
|
{
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:NSPopoverWillCloseNotification
|
|
|
|
object:self
|
|
|
|
userInfo:nil];
|
2013-04-21 13:45:20 +00:00
|
|
|
}
|
|
|
|
|
2013-04-21 21:32:36 +00:00
|
|
|
- (id) initWithCoder: (NSCoder *)coder
|
2013-04-21 13:45:20 +00:00
|
|
|
{
|
2013-04-21 21:32:36 +00:00
|
|
|
if (nil != (self = [super initWithCoder:coder]))
|
2013-04-21 13:45:20 +00:00
|
|
|
{
|
2013-04-21 21:32:36 +00:00
|
|
|
if (YES == [coder allowsKeyedCoding])
|
2013-04-21 13:45:20 +00:00
|
|
|
{
|
2013-04-21 21:32:36 +00:00
|
|
|
_appearance = [coder decodeIntForKey: @"NSAppearance"];
|
|
|
|
_behavior = [coder decodeIntForKey: @"NSBehavior"];
|
|
|
|
_animates = [coder decodeBoolForKey: @"NSAnimates"];
|
|
|
|
_contentSize.width = [coder decodeDoubleForKey: @"NSContentWidth"];
|
|
|
|
_contentSize.height = [coder decodeDoubleForKey: @"NSContentHeight"];
|
2013-04-24 09:25:56 +00:00
|
|
|
[self setContentViewController:[coder decodeObjectForKey:@"NSContentViewController"]];
|
2013-04-21 13:45:20 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-04-21 21:32:36 +00:00
|
|
|
[coder decodeValueOfObjCType: @encode(NSInteger) at: &_appearance];
|
|
|
|
[coder decodeValueOfObjCType: @encode(NSInteger) at: &_behavior];
|
|
|
|
[coder decodeValueOfObjCType: @encode(BOOL) at: &_animates];
|
|
|
|
[coder decodeValueOfObjCType: @encode(CGFloat) at: &_contentSize.width];
|
|
|
|
[coder decodeValueOfObjCType: @encode(CGFloat) at: &_contentSize.height];
|
2013-04-24 09:25:56 +00:00
|
|
|
[self setContentViewController:[coder decodeObject]];
|
2013-04-21 13:45:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2013-04-21 21:32:36 +00:00
|
|
|
- (void) encodeWithCoder: (NSCoder *)coder
|
2013-04-21 13:45:20 +00:00
|
|
|
{
|
|
|
|
[super encodeWithCoder:coder];
|
2013-04-21 21:32:36 +00:00
|
|
|
if (YES == [coder allowsKeyedCoding])
|
2013-04-21 13:45:20 +00:00
|
|
|
{
|
2013-04-21 21:32:36 +00:00
|
|
|
[coder encodeInt: _appearance forKey: @"NSAppearance"];
|
|
|
|
[coder encodeInt: _behavior forKey: @"NSBehavior"];
|
|
|
|
[coder encodeBool: _animates forKey: @"NSAnimates"];
|
|
|
|
[coder encodeDouble: _contentSize.width forKey: @"NSContentWidth"];
|
|
|
|
[coder encodeDouble: _contentSize.height forKey: @"NSContentHeight"];
|
2013-04-24 09:25:56 +00:00
|
|
|
[coder encodeObject:_contentViewController forKey:@"NSContentViewController"];
|
2013-04-21 13:45:20 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-04-21 21:32:36 +00:00
|
|
|
[coder encodeValueOfObjCType: @encode(NSInteger) at: &_appearance];
|
|
|
|
[coder encodeValueOfObjCType: @encode(NSInteger) at: &_behavior];
|
|
|
|
[coder encodeValueOfObjCType: @encode(BOOL) at: &_animates];
|
|
|
|
[coder encodeValueOfObjCType: @encode(CGFloat) at: &_contentSize.width];
|
|
|
|
[coder encodeValueOfObjCType: @encode(CGFloat) at: &_contentSize.height];
|
2013-04-24 09:25:56 +00:00
|
|
|
[coder encodeObject:_contentViewController];
|
2023-10-01 11:47:05 +00:00
|
|
|
}
|
2013-04-21 13:45:20 +00:00
|
|
|
}
|
2021-10-02 21:28:24 +00:00
|
|
|
|
2013-04-21 13:45:20 +00:00
|
|
|
@end
|