Search code examples
applescript-objc

How to create a Popover view with Applescript?


I'd like to know how to display a message by clicking a popover style button, could anyone here guide me to do this? For example, clicking a button opens a Popover view informing me of my IP.


Solution

  • An NSPopover is just a view that you can show at some location in another view, so you can show it from the button's action handler.

    For an example, create whatever you are wanting to put in the popover, such as an NSTextField, then create an NSViewController large enough to contain it. Next, create the NSPopover, set its contentViewController to the view controller, and show it via its showRelativeToRect:ofView:preferredEdge: at the desired location:

    use framework "Cocoa"
    
    property theWindow : missing value -- the main window
    
    on run -- run on main thread if using the Script Editor
        if current application's NSThread's isMainThread() as boolean then
            doStuff()
        else
            my performSelectorOnMainThread:"doStuff" withObject:(missing value) waitUntilDone:true
        end if
    end run
    
    to doStuff() -- make a window to put the example stuff in
        set theWindow to current application's NSWindow's alloc's initWithContentRect:{{200, 400}, {200, 100}} styleMask:7 backing:(current application's NSBackingStoreBuffered) defer:true
        theWindow's contentView's addSubview:(my makeButtonWithTitle:"Button" atLocation:{60, 40})
        theWindow's makeKeyAndOrderFront:me
    end doStuff
    
    to makeButtonWithTitle:title atLocation:location -- make a button at {x, y}
        tell (current application's NSButton's buttonWithTitle:title target:me action:"buttonAction:") -- 10.12 Sierra and later
            its setFrameOrigin:location
            its sizeToFit() -- fit to the title
            its setRefusesFirstResponder:true -- no highlight
            return it
        end tell
    end makeButtonWithTitle:atLocation:
    
    on buttonAction:sender -- do something when the button is clicked
        set title to sender's title
        set testString to "This is some popover text
    located at " & quoted form of (title as text) & "." -- whatever
        set {{x, y}, {width, height}} to (sender's frame()) as list -- for adjusting the location of the pointer
        set x to x + (width div 2) -- center horizontally
        set y to y + (height div 2) -- center vertically
        my showPopoverWithMessage:testString atPoint:{x, y} inView:(sender's |window|'s contentView()) -- use the window the button is in for the view
    end buttonAction:
    
    to showPopoverWithMessage:theMessage atPoint:thePoint inView:theView -- build and show the popover
        set textField to makeTextField() -- make a text field
        textField's setStringValue:theMessage -- put something in it
        textField's sizeToFit() -- resize the text field to fit the string
        set {width, height} to second item of (textField's frame as list) -- to size the view to the text field
        set popoverView to current application's NSView's alloc's initWithFrame:{{0, 0}, {width + 15, height + 15}} -- make a view to hold everything
        popoverView's addSubview:textField -- put the text field in it
        set popoverViewController to current application's NSViewController's alloc's init -- make a controller for the popover view
        popoverViewController's setView:popoverView -- set the view to it
    
        tell current application's NSPopover's alloc's init() -- make the popover
            its setContentViewController:popoverViewController
            its setBehavior:(current application's NSPopoverBehaviorTransient)
            its showRelativeToRect:{thePoint, {1, 1}} ofView:theView preferredEdge:(current application's NSMaxYEdge) -- and show it
        end tell
    end showPopoverWithMessage:atPoint:inView:
    
    to makeTextField() -- make a text field for the popover
        tell (current application's NSTextField's alloc's initWithFrame:{{10, 10}, {100, 100}})
            its setBordered:false
            its setDrawsBackground:false -- label
            its setRefusesFirstResponder:true -- no highlight
            its setAlignment:(current application's NSTextAlignmentCenter) -- or whatever
            its setFont:(current application's NSFont's fontWithName:"Noteworthy Bold" |size|:42)
            its setTextColor:(current application's NSColor's redColor)
            return it
        end tell
    end makeTextField