From 15547b2097cb09b702caed0c303575fba85688d8 Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Tue, 17 May 2022 16:18:12 +0100 Subject: [PATCH] Rework dialog icons. --- cmd/zenity/main.go | 22 +++++++++------------- entry_darwin.go | 11 ++++++----- msg_darwin.go | 13 +++++++------ msg_test.go | 4 ++-- msg_windows.go | 10 +++++----- pwd_darwin.go | 11 ++++++----- util_unix.go | 4 ++-- zenity.go | 30 +++++++++++++++++++----------- zenity_test.go | 1 + 9 files changed, 57 insertions(+), 49 deletions(-) diff --git a/cmd/zenity/main.go b/cmd/zenity/main.go index 2627c6c..0eda11d 100644 --- a/cmd/zenity/main.go +++ b/cmd/zenity/main.go @@ -401,27 +401,23 @@ func loadFlags() []zenity.Option { opts = append(opts, zenity.DefaultCancel()) } - var ico zenity.DialogIcon switch icon { - case unspecified: - ico = 0 case "error", "dialog-error": - ico = zenity.ErrorIcon + opts = append(opts, zenity.ErrorIcon) case "info", "dialog-information": - ico = zenity.InfoIcon + opts = append(opts, zenity.InfoIcon) case "question", "dialog-question": - ico = zenity.QuestionIcon + opts = append(opts, zenity.QuestionIcon) case "important", "warning", "dialog-warning": - ico = zenity.WarningIcon + opts = append(opts, zenity.WarningIcon) case "dialog-password": - ico = zenity.PasswordIcon + opts = append(opts, zenity.PasswordIcon) case "": - ico = zenity.NoIcon + opts = append(opts, zenity.NoIcon) + case unspecified: + // default: - opts = append(opts, zenity.CustomIcon(ingestPath(icon))) - } - if ico != 0 { - opts = append(opts, ico) + opts = append(opts, zenity.Icon(ingestPath(icon))) } // Message options diff --git a/entry_darwin.go b/entry_darwin.go index 80b20f1..952cb6d 100644 --- a/entry_darwin.go +++ b/entry_darwin.go @@ -14,14 +14,15 @@ func entry(text string, opts options) (string, error) { data.Options.Answer = &opts.entryText data.Options.Hidden = opts.hideText data.Options.Timeout = zenutil.Timeout - if opts.customIcon != "" { - _, err := os.Stat(opts.customIcon) + switch i := opts.icon.(type) { + case string: + _, err := os.Stat(i) if err != nil { return "", err } - data.IconPath = opts.customIcon - } else { - data.Options.Icon = opts.icon.String() + data.IconPath = i + case DialogIcon: + data.Options.Icon = i.String() } data.SetButtons(getButtons(true, true, opts)) diff --git a/msg_darwin.go b/msg_darwin.go index cb14863..22b7628 100644 --- a/msg_darwin.go +++ b/msg_darwin.go @@ -13,7 +13,7 @@ func message(kind messageKind, text string, opts options) error { // dialog is more flexible, alert prettier var dialog bool - if opts.icon != 0 || opts.customIcon != "" { // use if we want to show a specific icon + if opts.icon != nil { // use if we want to show a specific icon dialog = true } else if kind == questionKind && opts.cancelLabel == nil { // use for questions with default buttons dialog = true @@ -22,14 +22,15 @@ func message(kind messageKind, text string, opts options) error { if dialog { data.Operation = "displayDialog" data.Options.Title = opts.title - if opts.customIcon != "" { - _, err := os.Stat(opts.customIcon) + switch i := opts.icon.(type) { + case string: + _, err := os.Stat(i) if err != nil { return err } - data.IconPath = opts.customIcon - } else { - data.Options.Icon = opts.icon.String() + data.IconPath = i + case DialogIcon: + data.Options.Icon = i.String() } } else { data.Operation = "displayAlert" diff --git a/msg_test.go b/msg_test.go index 4983438..c67d2dd 100644 --- a/msg_test.go +++ b/msg_test.go @@ -40,10 +40,10 @@ func ExampleQuestion() { // Output: } -func ExampleCustomIcon() { +func ExampleIcon_custom() { zenity.Info("All updates are complete.", zenity.Title("Information"), - zenity.CustomIcon("testdata/icon.png")) + zenity.Icon("testdata/icon.png")) // Output: } diff --git a/msg_windows.go b/msg_windows.go index d3740c7..f3d44ee 100644 --- a/msg_windows.go +++ b/msg_windows.go @@ -37,7 +37,7 @@ func message(kind messageKind, text string, opts options) error { flags |= _MB_ICONWARNING case InfoIcon: flags |= _MB_ICONINFORMATION - case unspecifiedIcon: + case nil: switch kind { case errorKind: flags |= _MB_ICONERROR @@ -60,7 +60,7 @@ func message(kind messageKind, text string, opts options) error { defer setup()() - if opts.ctx != nil || opts.okLabel != nil || opts.cancelLabel != nil || opts.extraButton != nil || opts.customIcon != "" { + if opts.ctx != nil || opts.okLabel != nil || opts.cancelLabel != nil || opts.extraButton != nil || opts.icon != nil { unhook, err := hookMessageDialog(kind, opts) if err != nil { return err @@ -114,13 +114,13 @@ func hookMessageDialogCallback(wnd uintptr, lparam *options) uintptr { setWindowText.Call(wnd, strptr(*text)) } - if ctl == 20 /*IDC_STATIC_OK*/ && lparam.customIcon != "" { + if i, ok := lparam.icon.(string); ok && ctl == 20 /*IDC_STATIC_OK*/ { var icon uintptr - data, _ := os.ReadFile(lparam.customIcon) + data, _ := os.ReadFile(i) switch { case bytes.HasPrefix(data, []byte("\x00\x00\x01\x00")): icon, _, _ = loadImage.Call(0, - strptr(lparam.customIcon), + strptr(i), 1, /*IMAGE_ICON*/ 0, 0, 0x00008050 /*LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_SHARED*/) diff --git a/pwd_darwin.go b/pwd_darwin.go index b93c7cf..c9ce289 100644 --- a/pwd_darwin.go +++ b/pwd_darwin.go @@ -18,14 +18,15 @@ func password(opts options) (string, string, error) { data.Separator = zenutil.Separator data.Options.Title = opts.title data.Options.Timeout = zenutil.Timeout - if opts.customIcon != "" { - _, err := os.Stat(opts.customIcon) + switch i := opts.icon.(type) { + case string: + _, err := os.Stat(i) if err != nil { return "", "", err } - data.IconPath = opts.customIcon - } else { - data.Options.Icon = opts.icon.String() + data.IconPath = i + case DialogIcon: + data.Options.Icon = i.String() } data.SetButtons(getButtons(true, true, opts)) diff --git a/util_unix.go b/util_unix.go index 297cb45..df98a54 100644 --- a/util_unix.go +++ b/util_unix.go @@ -42,8 +42,8 @@ func appendWidthHeight(args []string, opts options) []string { } func appendIcon(args []string, opts options) []string { - if opts.customIcon != "" { - args = append(args, "--window-icon", opts.customIcon) + if i, ok := opts.icon.(string); ok { + args = append(args, "--window-icon", i) } switch opts.icon { case ErrorIcon: diff --git a/zenity.go b/zenity.go index 9d40f43..221b037 100644 --- a/zenity.go +++ b/zenity.go @@ -18,6 +18,9 @@ import ( "github.com/ncruces/zenity/internal/zenutil" ) +// Remove after 1.18. +type any = interface{} + func stringPtr(s string) *string { return &s } // ErrCanceled is returned when the cancel button is pressed, @@ -38,9 +41,8 @@ type options struct { okLabel *string cancelLabel *string extraButton *string - icon DialogIcon - customIcon string defaultCancel bool + icon any // Message options noWrap bool @@ -139,14 +141,12 @@ func DefaultCancel() Option { type DialogIcon int func (i DialogIcon) apply(o *options) { - o.customIcon = "" o.icon = i } // The stock dialog icons. const ( - unspecifiedIcon DialogIcon = iota - ErrorIcon + ErrorIcon DialogIcon = iota WarningIcon InfoIcon QuestionIcon @@ -156,15 +156,23 @@ const ( // Icon returns an Option to set the dialog icon. // -// Tip: use DialogIcon directly. -func Icon(icon DialogIcon) Option { return icon } +// Icon accepts a DialogIcon, or a string. +// The string can be a GTK icon name (Unix), or a path (Windows and macOS). +func Icon(icon any) Option { + switch icon.(type) { + case string: + case DialogIcon: + default: + panic("interface conversion: expected string or DialogIcon") + } + return funcOption(func(o *options) { o.icon = icon }) +} // CustomIcon returns an Option to set a custom dialog icon, loaded from a file. +// +// Deprecated: use Icon instead. func CustomIcon(path string) Option { - return funcOption(func(o *options) { - o.icon = unspecifiedIcon - o.customIcon = path - }) + return Icon(path) } // Context returns an Option to set a Context that can dismiss the dialog. diff --git a/zenity_test.go b/zenity_test.go index 9951a75..0d37714 100644 --- a/zenity_test.go +++ b/zenity_test.go @@ -24,6 +24,7 @@ func Test_applyOptions(t *testing.T) { {name: "ExtraButton", args: ExtraButton("Extra"), want: options{extraButton: stringPtr("Extra")}}, {name: "DefaultCancel", args: DefaultCancel(), want: options{defaultCancel: true}}, {name: "Icon", args: Icon(ErrorIcon), want: options{icon: ErrorIcon}}, + {name: "Icon", args: Icon("error"), want: options{icon: "error"}}, // Message options {name: "NoWrap", args: NoWrap(), want: options{noWrap: true}},