Opacity slider in "choose color" color picker

I’m working on a free/open-source VS Code extension that provides a macOS native color picker for working with CSS/HTML/hex colors inside VS Code. The extension opens the color picker via AppleScript like so:

tell current application to choose color default color {0, 0, 0}

It works very well, but the color picker appears without an opacity slider. The ability to change opacity could be very useful to web-developers.

Here’s what I mean:

As far as I understand, the appearance of the opacity slider is controlled by NSColorPanel’s instance property “showsAlpha”, as described here:
https://developer.apple.com/documentation/appkit/nscolorpanel/1525279-showsalpha.

I’m searching for some AppleScript dark magic to enable this instance property, or any other way to start the color picker with the opacity slider.

Any help would be appreciated!

You might get some ideas here:

https://macscripter.net/viewtopic.php?id=44549

Thank you for the response. I checked that topic prior to posting, but I couldn’t make anything out of it.Those code snippets are way above my AppleScript knowledge. And as far as I could tell, the snippets do not manipulate NSColorList’s instance properties.

Shane, :slight_smile:
thank you.

I removed some problematic peaces from your code, and now I have color picker with opacity slider. I added returning the opacity component too:


use AppleScript version "2.3.1"
use scripting additions
use framework "Foundation"
use framework "AppKit"
global rgbValues

set rgbValues to missing value -- start off empty
set thePicker to current application's NSColorPanel's sharedColorPanel()
thePicker's setShowsAlpha:true -- ADDED
current application's NSColorPanel's setPickerMode:(current application's NSWheelModeColorPanel)

-- set what happens when you click
thePicker's setTarget:me -- message will be sent to this script
thePicker's setAction:"colorPicked:" -- message will call handler of this name

-- show the panel
thePicker's orderFront:me

repeat -- loop until the user clicks
	if rgbValues is not missing value then exit repeat
	delay 0.01
end repeat
return rgbValues

-- gets called when you click
on colorPicked:sender
	-- get the color
	set theColor to sender's |color|()
	-- convert to correct colorspace
	set newColor to theColor's colorUsingColorSpace:(current application's NSColorSpace's deviceRGBColorSpace())
	-- get components
	set theRed to newColor's redComponent()
	set theBlue to newColor's blueComponent()
	set theGreen to newColor's greenComponent()
	set theOpacity to newColor's alphaComponent()
	-- close panel
	sender's orderOut:me
	-- set property
	set rgbValues to {theRed * 255 as integer, theGreen * 255 as integer, theBlue * 255 as integer, theOpacity * 100 as integer}
end colorPicked:

Wow, thanks KniazidisR! But how can I run this script? My Script Editor crashes when I try to run it.

The previous script allows only one of 2 settings at time. Here is enhanced version. It allows the user to select sequentially opacity, then color, or vice versa:


use AppleScript version "2.3.1"
use scripting additions
use framework "Foundation"
use framework "AppKit"
global rgbValues

display dialog "\"Color Picker script\".

  Pick the Opacity first, then pick Color, or vice versa"

set rgbValues to missing value -- start off empty
set thePicker to current application's NSColorPanel's sharedColorPanel()
thePicker's setShowsAlpha:true -- ADDED
current application's NSColorPanel's setPickerMode:(current application's NSWheelModeColorPanel)

-- set what happens when you click
thePicker's setTarget:me -- message will be sent to this script
thePicker's setAction:"colorPicked:" -- message will call handler of this name

set rgbValues to missing value -- start off empty
-- show the panel
thePicker's orderFront:me
repeat -- loop until the user clicks
	if rgbValues is not missing value then exit repeat
	delay 0.01
end repeat
set rgbValues to missing value -- start off empty again
-- show the panel
thePicker's orderFront:me
repeat -- loop until the user clicks
	if rgbValues is not missing value then exit repeat
	delay 0.01
end repeat

return rgbValues

-- gets called when you click
on colorPicked:sender
	-- get the color
	set theColor to sender's |color|()
	-- convert to correct colorspace
	set newColor to theColor's colorUsingColorSpace:(current application's NSColorSpace's deviceRGBColorSpace())
	-- get components
	set theRed to newColor's redComponent()
	set theBlue to newColor's blueComponent()
	set theGreen to newColor's greenComponent()
	set theOpacity to newColor's alphaComponent()
	-- close panel
	sender's orderOut:me
	-- set property
	set rgbValues to {theRed * 255 as integer, theGreen * 255 as integer, theBlue * 255 as integer, theOpacity * 100 as integer}
end colorPicked:

I checked the update and I still don’t see the opacity slider. This is how it normally looks like:

Thanks for helping out!

You should run it on main thread, that is, as application. Or, press shortcut Command+Control+R in the Script Editor. This runs it as script too. In the Script Debugger press shortcut Command+Option+R, then run script.

Thanks, I installed Script Debugger, ran the script successfully, but still the opacity slider is nowhere to be seen.

I’m puzzled.
I tested using ctrl + cmd + R.
I didn’t see the disk with numerous colors.
If I move the slider dedicated to opacity, I’m not allowed to change the color.
If I re-run the script, and trigger the pipette, I may select a color but the dialog disappear without letting me setting the opacity.
If I save the script as an application, I see the disk with numerous colors but once again I can’t set two parameters, the color OR the opacity.
Is it the designed behavior ?

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) lundi 4 mai 2020 19:28:41

The OP was right. After creating thePicker need this code line for stability of color picker:

thePicker's setShowsAlpha:true

I will update 2 my scripts. (the changes is marked with ADDED)

Now, what puzzle the Yvan Koenig. When you choose firstly the opacity it remains on second show too .When you choose firstly the color it remains on second show too. The final result is correct values of both values.

This is the desired behavior (demonstrated via Apple Pages):

Simple solution:


use AppleScript version "2.3.1"
use scripting additions
use framework "Foundation"
use framework "AppKit"

set thePicker to current application's NSColorPanel's sharedColorPanel()
thePicker's setShowsAlpha:true -- ADDED
current application's NSColorPanel's setPickerMode:(current application's NSWheelModeColorPanel)

-- show the panel
thePicker's orderFront:me

set appName to name of current application
tell application "System Events" to tell process appName
	repeat until window "Colours" exists
		delay 0.02
	end repeat
	repeat while window "Colours" exists
		delay 0.02
		set theColor to thePicker's |color|()
		-- convert to correct colorspace
		set newColor to theColor's colorUsingColorSpace:(current application's NSColorSpace's deviceRGBColorSpace())
		-- get components
		set theRed to newColor's redComponent()
		set theBlue to newColor's blueComponent()
		set theGreen to newColor's greenComponent()
		set theOpacity to newColor's alphaComponent()
	end repeat
end tell

set rgbValues to {theRed * 255 as integer, theGreen * 255 as integer, theBlue * 255 as integer, theOpacity * 100 as integer}

I apologizes but when I have selected a color, moving the cursor to the slider force the dialog to close.
I must re-run the script to adjust the slider.
Is it really the designed behavior ?

Yvan, :confused:

The previous scripts are just attempts on my part to bring the original from Shane to working condition. Although he is not to blame for this “strange” behavior of the slider. He published his script about registering a mouse click from a user. And very successful.

But, let people read my previous post if you don’t read it yourself. The last script has correct behavior. The last script is already a solution, although there may be something better.

No. Unfortunately, it would be very inconvenient to the end-user.

KniazidisR I wonder if there is a way to combine this piece:

set thePicker to current application's NSColorPanel's sharedColorPanel()
thePicker's setShowsAlpha:true -- ADDED

… with this:

tell current application to choose color default color {0, 0, 0}

Thanks!!

You missed 2 of my posts. I do not know how to help you if you do not read carefully. Combination of choose color and NSColorPanel should be impossible. And, no need, as I think.

I missed nothing.

What I assume is that your code allow to choose the color and its opacity as is done in the messages #1, #7 and #12.
Even the script in message #13 doesn’t allow that.

I didn’t blame this behavior, I asked if it’s the designed one.

It’s just different than the way the dialog behaves in Apple’s applications like Pages or Numbers which allow me to define a color and its opacity without quitting the dedicated dialog.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) lundi 4 mai 2020 21:58:42

2 posts missed the OP. I turned to him because you had already confused him. But now I will go to work, and in the morning, of course, the long-awaited solution to the problem from Yvan Koenig awaits me. But even if this happens, I will only be glad. Because there are very few Color Picker programming examples.

KniazidisR,

Thanks for having a go at fixing my script. I posted the pointer late at night, without checking, and didn’t realize that the structure of the panel has changed since then.

This version lets you choose both color and opacity, and doesn’t return the values until the picker is closed. Again, it requires the main thread.

use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"
property rgbValues : missing value
property windowClosed : missing value

set thePicker to current application's NSColorPanel's sharedColorPanel()
current application's NSColorPanel's setPickerMode:(current application's NSWheelModeColorPanel)
thePicker's setShowsAlpha:true
thePicker's setDelegate:me -- so windowWillClose: gets called
set my windowClosed to false

-- set what happens when you click
thePicker's setTarget:me -- message will be sent to this script
thePicker's setAction:"colorPicked:" -- message will call handler of this name

-- show the panel
thePicker's orderFront:me

repeat -- loop until the user clicks
	if windowClosed then exit repeat
	delay 0.1
end repeat
return rgbValues

on windowWillClose:notif
	set my windowClosed to true
end windowWillClose:

-- gets called when you click
on colorPicked:sender
	-- get the color
	set theColor to sender's |color|()
	-- convert to correct colorspace
	set newColor to theColor's colorUsingColorSpace:(current application's NSColorSpace's deviceRGBColorSpace())
	-- get components
	set theRed to newColor's redComponent()
	set theBlue to newColor's blueComponent()
	set theGreen to newColor's greenComponent()
	set theOpacity to newColor's alphaComponent()
	-- set property
	set rgbValues to {theRed * 255 as integer, theGreen * 255 as integer, theBlue * 255 as integer, theOpacity * 100 as integer}
end colorPicked: