From 0728bdf5ad54173f6acaa9f07e1165d6a011268a Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Tue, 21 Jan 2020 16:13:45 +0000 Subject: [PATCH] Color dialog (linux). --- README.md | 1 + cmd/zenity/main.go | 54 ++++++++++++++++--- color_darwin.go | 4 +- color_test.go | 4 +- color_unix.go | 40 ++++++++++++++ color_windows.go | 4 +- internal/zenutil/color.go | 16 +++++- internal/zenutil/osa_generated.go | 2 +- internal/zenutil/osascripts/color.applescript | 2 +- internal/zenutil/run_darwin.go | 2 +- zenity.go | 2 + 11 files changed, 114 insertions(+), 17 deletions(-) create mode 100644 color_unix.go diff --git a/README.md b/README.md index 5c42765..723b14e 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ Lots of things are missing. For now, these are the only implemented dialogs: * [message](https://github.com/ncruces/zenity/wiki/Message-dialog) (error, info, question, warning) * [file selection](https://github.com/ncruces/zenity/wiki/File-Selection-dialog) +* [color selection](https://github.com/ncruces/zenity/wiki/Color-Selection-dialog) Behavior on Windows, macOS and other Unixes might differ slightly. Some of that is intended (reflecting platform differences), diff --git a/cmd/zenity/main.go b/cmd/zenity/main.go index 2dca13a..9bf3e6e 100644 --- a/cmd/zenity/main.go +++ b/cmd/zenity/main.go @@ -2,6 +2,7 @@ package main import ( "flag" + "image/color" "os" "os/exec" "path/filepath" @@ -16,11 +17,12 @@ import ( var ( // Application Options - errorDlg bool - infoDlg bool - warningDlg bool - questionDlg bool - fileSelectionDlg bool + errorDlg bool + infoDlg bool + warningDlg bool + questionDlg bool + fileSelectionDlg bool + colorSelectionDlg bool // General options title string @@ -46,6 +48,10 @@ var ( separator string fileFilters FileFilters + // Color selection options + initColor string + palette bool + // Windows specific options cygpath bool wslpath bool @@ -77,6 +83,9 @@ func main() { case multiple: lstResult(egestPaths(zenity.SelectFileMutiple(opts...))) } + + case colorSelectionDlg: + clrResult(zenity.SelectColor(opts...)) } flag.Usage() @@ -91,6 +100,7 @@ func setupFlags() { flag.BoolVar(&warningDlg, "warning", false, "Display warning dialog") flag.BoolVar(&questionDlg, "question", false, "Display question dialog") flag.BoolVar(&fileSelectionDlg, "file-selection", false, "Display file selection dialog") + flag.BoolVar(&colorSelectionDlg, "color-selection", false, "Display color selection dialog") // General options @@ -119,6 +129,10 @@ func setupFlags() { flag.StringVar(&separator, "separator", "|", "Set output separator character") flag.Var(&fileFilters, "file-filter", "Set a filename filter (NAME | PATTERN1 PATTERN2 ...)") + // Color selection options + flag.StringVar(&initColor, "color", "", "Set the color") + flag.BoolVar(&palette, "show-palette", false, "Show the palette") + // Windows specific options if runtime.GOOS == "windows" { flag.BoolVar(&cygpath, "cygpath", false, "Use cygpath for path translation (Windows only)") @@ -143,6 +157,9 @@ func validateFlags() { if fileSelectionDlg { n++ } + if colorSelectionDlg { + n++ + } if n != 1 { flag.Usage() os.Exit(-1) @@ -187,7 +204,9 @@ func loadFlags() []zenity.Option { // File selection options options = append(options, fileFilters.Build()) - options = append(options, zenity.Filename(ingestPath(filename))) + if filename != "" { + options = append(options, zenity.Filename(ingestPath(filename))) + } if directory { options = append(options, zenity.Directory()) } @@ -203,6 +222,15 @@ func loadFlags() []zenity.Option { zenutil.Separator = separator + // Color selection options + + if initColor != "" { + options = append(options, zenity.Color(zenutil.ParseColor(initColor))) + } + if palette { + options = append(options, zenity.ShowPalette()) + } + return options } @@ -251,6 +279,20 @@ func lstResult(l []string, err error) { os.Exit(0) } +func clrResult(c color.Color, err error) { + if err != nil { + os.Stderr.WriteString(err.Error()) + os.Stderr.WriteString(zenutil.LineBreak) + os.Exit(-1) + } + if c == nil { + os.Exit(1) + } + os.Stdout.WriteString(zenutil.UnparseColor(c)) + os.Stdout.WriteString(zenutil.LineBreak) + os.Exit(0) +} + func ingestPath(path string) string { if runtime.GOOS == "windows" && path != "" { var args []string diff --git a/color_darwin.go b/color_darwin.go index 1fe6d24..7ea7238 100644 --- a/color_darwin.go +++ b/color_darwin.go @@ -12,8 +12,8 @@ func SelectColor(options ...Option) (color.Color, error) { var data zenutil.Color if opts.color != nil { - r, g, b, _ := opts.color.RGBA() - data.Color = []uint32{r, g, b} + n := color.NRGBA64Model.Convert(opts.color).(color.NRGBA64) + data.Color = []uint16{n.R, n.G, n.B} } out, err := zenutil.Run("color", data) diff --git a/color_test.go b/color_test.go index 26baf03..846cd9b 100644 --- a/color_test.go +++ b/color_test.go @@ -8,13 +8,13 @@ import ( func ExampleSelectColor() { zenity.SelectColor( - zenity.Color(color.RGBA{R: 0x66, G: 0x33, B: 0x99, A: 0xff})) + zenity.Color(color.NRGBA{R: 0x66, G: 0x33, B: 0x99, A: 0x80})) // Output: } func ExampleSelectColor_palette() { zenity.SelectColor( zenity.ShowPalette(), - zenity.Color(color.RGBA{R: 0x66, G: 0x33, B: 0x99, A: 0xff})) + zenity.Color(color.NRGBA{R: 0x66, G: 0x33, B: 0x99, A: 0xff})) // Output: } diff --git a/color_unix.go b/color_unix.go new file mode 100644 index 0000000..d68514d --- /dev/null +++ b/color_unix.go @@ -0,0 +1,40 @@ +// +build !windows,!darwin + +package zenity + +import ( + "image/color" + "os/exec" + + "github.com/ncruces/zenity/internal/zenutil" +) + +// Display color selection dialog. +// +// Returns nil on cancel. +// +// Valid options: Title, Color, ShowPalette. +func SelectColor(options ...Option) (color.Color, error) { + opts := optsParse(options) + + args := []string{"--color-selection"} + + if opts.title != "" { + args = append(args, "--title", opts.title) + } + if opts.color != nil { + args = append(args, "--color", zenutil.UnparseColor(opts.color)) + } + if opts.palette { + args = append(args, "--show-palette") + } + + out, err := zenutil.Run(args) + if err, ok := err.(*exec.ExitError); ok && err.ExitCode() != 255 { + return nil, nil + } + if err != nil { + return nil, err + } + return zenutil.ParseColor(string(out)), nil +} diff --git a/color_windows.go b/color_windows.go index cefeec5..df22a97 100644 --- a/color_windows.go +++ b/color_windows.go @@ -34,8 +34,8 @@ func SelectColor(options ...Option) (color.Color, error) { if opts.color != nil { args.Flags |= 0x1 // CC_RGBINIT - r, g, b, _ := opts.color.RGBA() - args.RgbResult = (r >> 8 << 0) | (g >> 8 << 8) | (b >> 8 << 16) + n := color.NRGBAModel.Convert(opts.color).(color.NRGBA) + args.RgbResult = uint32(n.R) | (uint32(n.G) << 8) | (uint32(n.B) << 16) } if opts.palette { args.Flags |= 4 // CC_PREVENTFULLOPEN diff --git a/internal/zenutil/color.go b/internal/zenutil/color.go index 2c8011b..7e90ed8 100644 --- a/internal/zenutil/color.go +++ b/internal/zenutil/color.go @@ -39,6 +39,18 @@ func ParseColor(s string) color.Color { } } - c, _ := colornames.Map[strings.ToLower(s)] - return c + c, ok := colornames.Map[strings.ToLower(s)] + if ok { + return c + } + return nil +} + +func UnparseColor(c color.Color) string { + n := color.NRGBAModel.Convert(c).(color.NRGBA) + if n.A == 255 { + return fmt.Sprintf("rgb(%d,%d,%d)", n.R, n.G, n.B) + } else { + return fmt.Sprintf("rgba(%d,%d,%d,%f)", n.R, n.G, n.B, float32(n.A)/255) + } } diff --git a/internal/zenutil/osa_generated.go b/internal/zenutil/osa_generated.go index 2934ecd..c5c8b62 100644 --- a/internal/zenutil/osa_generated.go +++ b/internal/zenutil/osa_generated.go @@ -17,7 +17,7 @@ set c to choose color default color { {{index .Color 0}}, {{index .Color 1}}, {{ {{else -}} set c to choose color {{end}} -"rgb(" & (item 1 of c) div 257 & "," & (item 2 of c) div 257 & "," & (item 3 of c) div 257 & ")" +"rgb(" & (item 1 of c) div 256 & "," & (item 2 of c) div 256 & "," & (item 3 of c) div 256 & ")" end tell {{- end}} {{define "file" -}}var app = Application.currentApplication() diff --git a/internal/zenutil/osascripts/color.applescript b/internal/zenutil/osascripts/color.applescript index 3f31ace..53b5eeb 100644 --- a/internal/zenutil/osascripts/color.applescript +++ b/internal/zenutil/osascripts/color.applescript @@ -5,5 +5,5 @@ tell application (path to frontmost application as text) {{else -}} set c to choose color {{end}} - "rgb(" & (item 1 of c) div 257 & "," & (item 2 of c) div 257 & "," & (item 3 of c) div 257 & ")" + "rgb(" & (item 1 of c) div 256 & "," & (item 2 of c) div 256 & "," & (item 3 of c) div 256 & ")" end tell \ No newline at end of file diff --git a/internal/zenutil/run_darwin.go b/internal/zenutil/run_darwin.go index 92e0e0b..e5fe7ac 100644 --- a/internal/zenutil/run_darwin.go +++ b/internal/zenutil/run_darwin.go @@ -46,7 +46,7 @@ type File struct { } type Color struct { - Color []uint32 + Color []uint16 } type Msg struct { diff --git a/zenity.go b/zenity.go index 8db4ec8..2b54ae8 100644 --- a/zenity.go +++ b/zenity.go @@ -112,10 +112,12 @@ func (f FileFilters) Build() Option { // Color selection options +// Option to set the color. func Color(c color.Color) Option { return func(o *options) { o.color = c } } +// Option to show the palette. func ShowPalette() Option { return func(o *options) { o.palette = true } }