9

Is there any way to color NSPopover? Ive seen apps like facetab etc that have cool colors and resizeable popovers, how is this done?

Ay guides, hints?

Thanks.

cacau
  • 3,606
  • 3
  • 21
  • 42
Rasmus Styrk
  • 1,296
  • 2
  • 20
  • 36
  • For the record: the color of the "frame" (the arrow and a thin border) is something like `[NSColor colorWithCalibratedRed:0.980 green:0.955 blue:0.956 alpha:1.000]` — I "grabbed" this thanks to http://panic.com/~wade/picker – StuFF mc Nov 24 '13 at 23:08
  • This is a duplicate of: http://stackoverflow.com/questions/19978620/how-to-change-nspopover-background-color-include-triangle-part, where there is an interesting option to use the native NSPopover + private API to access the view used to draw the triangle (http://stackoverflow.com/a/29862351/9900) – charles May 28 '15 at 18:43
  • 1
    Please give this solution a try: http://stackoverflow.com/questions/19978620/how-to-change-nspopover-background-color-include-triangle-part/30660945#30660945 – Stefanf Jul 02 '15 at 14:14

7 Answers7

2

Set popover.contentViewController.view as a subclass of NSView with a custom background drawing (i.e. override drawRect: and fill a rect with your custom background color).

Then set the popover.appearance = NSPopoverAppearanceHUD to remove the default border around the view.

Note that there will still be a very thin border around the view, so if you want to remove it completely, you may want to use MAAttachedWindow or a similar solution.

Yoav
  • 5,962
  • 5
  • 39
  • 61
2

In Swift 4:

  1. Go to File->New File->Cocoa Class
  2. Name your class. eg. PopColor. Make sure it is a subclass of NSView
  3. Set the contents of the file to:
import Cocoa

class PopoverContentView:NSView {
    var backgroundView:PopoverBackgroundView?
    override func viewDidMoveToWindow() {
        super.viewDidMoveToWindow()
        if let frameView = self.window?.contentView?.superview {
            if backgroundView == nil {
                backgroundView = PopoverBackgroundView(frame: frameView.bounds)
                backgroundView!.autoresizingMask = NSView.AutoresizingMask([.width, .height]);
                frameView.addSubview(backgroundView!, positioned: NSWindow.OrderingMode.below, relativeTo: frameView)
            }
        }
    }
}

class PopoverBackgroundView:NSView {
    override func draw(_ dirtyRect: NSRect) {
        NSColor.green.set()
        self.bounds.fill()
    }
}
  1. In your storyboard, select the view which has your popover content and go to the Identity Inspector

  2. Set the Class to PopoverContentView

Your popover and its triangle will now be green.

Ribena
  • 1,086
  • 1
  • 11
  • 20
0

You can subclass NSView and set it as the NSPopover's view controller's view.

Raffael
  • 1,119
  • 10
  • 20
0

You can use MAAttachedWindow instead.

Yoav
  • 5,962
  • 5
  • 39
  • 61
0

Yes and no. Unfortunately NSPopover isn't designed to be customisable. You can use some simple hacks for adding additional background view behind contentViewController's view and colorise or customise it as you want. In this case, you can get the customisable background that will be masked the same as generic NSPopover border and tail.

For more details you can take a look at the code of NSPopover+MISSINGBackgroundView category that implements this approach or just use this piece of code as CocoaPod library.

Valentin Shergin
  • 7,166
  • 2
  • 50
  • 53
0

The complete code to change the color of NSPopover including the triangle is here:

I assume people have hooked the popover outlets and methods

#import "AppDelegate.h"

@interface MyPopoverBackgroundView : NSView
@end


@implementation MyPopoverBackgroundView

-(void)drawRect:(NSRect)dirtyRect
{
    [[NSColor redColor] set];
    NSRectFill(self.bounds);
}

@end

//===============================================================================================
@interface MyPopView : NSView
@end

@implementation MyPopView
-(void)viewDidMoveToWindow{
    NSView *aFrameView = [[self.window contentView] superview];
    MyPopoverBackgroundView * aBGView  =[[MyPopoverBackgroundView alloc] initWithFrame:aFrameView.bounds];
    aBGView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
    [aFrameView addSubview:aBGView positioned:NSWindowBelow relativeTo:aFrameView];
    [super viewDidMoveToWindow];
}
@end



//-----------------------------------------------------------------------------------------
@interface AppDelegate ()

@property (weak) IBOutlet NSWindow *window;
@end

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    // Insert code here to initialize your application

    //close when clicked outside
    [self.popover setBehavior:NSPopoverBehaviorTransient];


    //change its color
    MyPopView *myPopview = [MyPopView new];
    [self.popover.contentViewController.view addSubview:myPopview];
}


- (void)applicationWillTerminate:(NSNotification *)aNotification {
    // Insert code here to tear down your application
}


- (IBAction)closePopover:(id)sender {
    [self.popover close];
}

- (IBAction)showPopover:(id)sender {

    [self.popover showRelativeToRect:[sender bounds]
                              ofView:sender
                       preferredEdge:NSMaxYEdge];
}


@end
Anoop Vaidya
  • 46,283
  • 15
  • 111
  • 140
  • Could you give a bit more info for beginners on how to implement this? Cheers! – Ribena Jun 24 '18 at 04:04
  • @Ribena: I have added all the code - you need to copy-paste and change only the class name as `MyPopoverBackgroundView`, or create a class with this same name. And create popup and hook it in your xib. Or if you've some specific concern please let me know. – Anoop Vaidya Jun 25 '18 at 07:14
-4

This is what I did to change the popover color.

Assuming that you have properly defined your NSPopover:

//AppController.h
#import <Foundation/Foundation.h>

@interface AppController : NSObject
@property (weak) IBOutlet NSPopover errorPopover;
// whatever else you have ...
@end

//AppController.m
#import "AppController.h"

@implementation AppController
@synthesize errorPopover = _errorPopover;
// whatever else you have ...

-(IBAction)doSomethingThatCallsPopover:(id)sender {
_errorPopover.appearance = NSPopoverAppearanceHUD; //set color of error popup
[[self errorPopover] showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMaxXEdge];
}
@end

NSPopover Class Reference - I really wish they would provide usage code in the developer docs.

Vincent Mac
  • 421
  • 4
  • 8