Rework dialog icons.

This commit is contained in:
Nuno Cruces 2022-05-17 16:18:12 +01:00
parent 0b2f5d218d
commit 15547b2097
9 changed files with 57 additions and 49 deletions

View file

@ -401,27 +401,23 @@ func loadFlags() []zenity.Option {
opts = append(opts, zenity.DefaultCancel()) opts = append(opts, zenity.DefaultCancel())
} }
var ico zenity.DialogIcon
switch icon { switch icon {
case unspecified:
ico = 0
case "error", "dialog-error": case "error", "dialog-error":
ico = zenity.ErrorIcon opts = append(opts, zenity.ErrorIcon)
case "info", "dialog-information": case "info", "dialog-information":
ico = zenity.InfoIcon opts = append(opts, zenity.InfoIcon)
case "question", "dialog-question": case "question", "dialog-question":
ico = zenity.QuestionIcon opts = append(opts, zenity.QuestionIcon)
case "important", "warning", "dialog-warning": case "important", "warning", "dialog-warning":
ico = zenity.WarningIcon opts = append(opts, zenity.WarningIcon)
case "dialog-password": case "dialog-password":
ico = zenity.PasswordIcon opts = append(opts, zenity.PasswordIcon)
case "": case "":
ico = zenity.NoIcon opts = append(opts, zenity.NoIcon)
case unspecified:
//
default: default:
opts = append(opts, zenity.CustomIcon(ingestPath(icon))) opts = append(opts, zenity.Icon(ingestPath(icon)))
}
if ico != 0 {
opts = append(opts, ico)
} }
// Message options // Message options

View file

@ -14,14 +14,15 @@ func entry(text string, opts options) (string, error) {
data.Options.Answer = &opts.entryText data.Options.Answer = &opts.entryText
data.Options.Hidden = opts.hideText data.Options.Hidden = opts.hideText
data.Options.Timeout = zenutil.Timeout data.Options.Timeout = zenutil.Timeout
if opts.customIcon != "" { switch i := opts.icon.(type) {
_, err := os.Stat(opts.customIcon) case string:
_, err := os.Stat(i)
if err != nil { if err != nil {
return "", err return "", err
} }
data.IconPath = opts.customIcon data.IconPath = i
} else { case DialogIcon:
data.Options.Icon = opts.icon.String() data.Options.Icon = i.String()
} }
data.SetButtons(getButtons(true, true, opts)) data.SetButtons(getButtons(true, true, opts))

View file

@ -13,7 +13,7 @@ func message(kind messageKind, text string, opts options) error {
// dialog is more flexible, alert prettier // dialog is more flexible, alert prettier
var dialog bool 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 dialog = true
} else if kind == questionKind && opts.cancelLabel == nil { // use for questions with default buttons } else if kind == questionKind && opts.cancelLabel == nil { // use for questions with default buttons
dialog = true dialog = true
@ -22,14 +22,15 @@ func message(kind messageKind, text string, opts options) error {
if dialog { if dialog {
data.Operation = "displayDialog" data.Operation = "displayDialog"
data.Options.Title = opts.title data.Options.Title = opts.title
if opts.customIcon != "" { switch i := opts.icon.(type) {
_, err := os.Stat(opts.customIcon) case string:
_, err := os.Stat(i)
if err != nil { if err != nil {
return err return err
} }
data.IconPath = opts.customIcon data.IconPath = i
} else { case DialogIcon:
data.Options.Icon = opts.icon.String() data.Options.Icon = i.String()
} }
} else { } else {
data.Operation = "displayAlert" data.Operation = "displayAlert"

View file

@ -40,10 +40,10 @@ func ExampleQuestion() {
// Output: // Output:
} }
func ExampleCustomIcon() { func ExampleIcon_custom() {
zenity.Info("All updates are complete.", zenity.Info("All updates are complete.",
zenity.Title("Information"), zenity.Title("Information"),
zenity.CustomIcon("testdata/icon.png")) zenity.Icon("testdata/icon.png"))
// Output: // Output:
} }

View file

@ -37,7 +37,7 @@ func message(kind messageKind, text string, opts options) error {
flags |= _MB_ICONWARNING flags |= _MB_ICONWARNING
case InfoIcon: case InfoIcon:
flags |= _MB_ICONINFORMATION flags |= _MB_ICONINFORMATION
case unspecifiedIcon: case nil:
switch kind { switch kind {
case errorKind: case errorKind:
flags |= _MB_ICONERROR flags |= _MB_ICONERROR
@ -60,7 +60,7 @@ func message(kind messageKind, text string, opts options) error {
defer setup()() 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) unhook, err := hookMessageDialog(kind, opts)
if err != nil { if err != nil {
return err return err
@ -114,13 +114,13 @@ func hookMessageDialogCallback(wnd uintptr, lparam *options) uintptr {
setWindowText.Call(wnd, strptr(*text)) 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 var icon uintptr
data, _ := os.ReadFile(lparam.customIcon) data, _ := os.ReadFile(i)
switch { switch {
case bytes.HasPrefix(data, []byte("\x00\x00\x01\x00")): case bytes.HasPrefix(data, []byte("\x00\x00\x01\x00")):
icon, _, _ = loadImage.Call(0, icon, _, _ = loadImage.Call(0,
strptr(lparam.customIcon), strptr(i),
1, /*IMAGE_ICON*/ 1, /*IMAGE_ICON*/
0, 0, 0, 0,
0x00008050 /*LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_SHARED*/) 0x00008050 /*LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_SHARED*/)

View file

@ -18,14 +18,15 @@ func password(opts options) (string, string, error) {
data.Separator = zenutil.Separator data.Separator = zenutil.Separator
data.Options.Title = opts.title data.Options.Title = opts.title
data.Options.Timeout = zenutil.Timeout data.Options.Timeout = zenutil.Timeout
if opts.customIcon != "" { switch i := opts.icon.(type) {
_, err := os.Stat(opts.customIcon) case string:
_, err := os.Stat(i)
if err != nil { if err != nil {
return "", "", err return "", "", err
} }
data.IconPath = opts.customIcon data.IconPath = i
} else { case DialogIcon:
data.Options.Icon = opts.icon.String() data.Options.Icon = i.String()
} }
data.SetButtons(getButtons(true, true, opts)) data.SetButtons(getButtons(true, true, opts))

View file

@ -42,8 +42,8 @@ func appendWidthHeight(args []string, opts options) []string {
} }
func appendIcon(args []string, opts options) []string { func appendIcon(args []string, opts options) []string {
if opts.customIcon != "" { if i, ok := opts.icon.(string); ok {
args = append(args, "--window-icon", opts.customIcon) args = append(args, "--window-icon", i)
} }
switch opts.icon { switch opts.icon {
case ErrorIcon: case ErrorIcon:

View file

@ -18,6 +18,9 @@ import (
"github.com/ncruces/zenity/internal/zenutil" "github.com/ncruces/zenity/internal/zenutil"
) )
// Remove after 1.18.
type any = interface{}
func stringPtr(s string) *string { return &s } func stringPtr(s string) *string { return &s }
// ErrCanceled is returned when the cancel button is pressed, // ErrCanceled is returned when the cancel button is pressed,
@ -38,9 +41,8 @@ type options struct {
okLabel *string okLabel *string
cancelLabel *string cancelLabel *string
extraButton *string extraButton *string
icon DialogIcon
customIcon string
defaultCancel bool defaultCancel bool
icon any
// Message options // Message options
noWrap bool noWrap bool
@ -139,14 +141,12 @@ func DefaultCancel() Option {
type DialogIcon int type DialogIcon int
func (i DialogIcon) apply(o *options) { func (i DialogIcon) apply(o *options) {
o.customIcon = ""
o.icon = i o.icon = i
} }
// The stock dialog icons. // The stock dialog icons.
const ( const (
unspecifiedIcon DialogIcon = iota ErrorIcon DialogIcon = iota
ErrorIcon
WarningIcon WarningIcon
InfoIcon InfoIcon
QuestionIcon QuestionIcon
@ -156,15 +156,23 @@ const (
// Icon returns an Option to set the dialog icon. // Icon returns an Option to set the dialog icon.
// //
// Tip: use DialogIcon directly. // Icon accepts a DialogIcon, or a string.
func Icon(icon DialogIcon) Option { return icon } // 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. // CustomIcon returns an Option to set a custom dialog icon, loaded from a file.
//
// Deprecated: use Icon instead.
func CustomIcon(path string) Option { func CustomIcon(path string) Option {
return funcOption(func(o *options) { return Icon(path)
o.icon = unspecifiedIcon
o.customIcon = path
})
} }
// Context returns an Option to set a Context that can dismiss the dialog. // Context returns an Option to set a Context that can dismiss the dialog.

View file

@ -24,6 +24,7 @@ func Test_applyOptions(t *testing.T) {
{name: "ExtraButton", args: ExtraButton("Extra"), want: options{extraButton: stringPtr("Extra")}}, {name: "ExtraButton", args: ExtraButton("Extra"), want: options{extraButton: stringPtr("Extra")}},
{name: "DefaultCancel", args: DefaultCancel(), want: options{defaultCancel: true}}, {name: "DefaultCancel", args: DefaultCancel(), want: options{defaultCancel: true}},
{name: "Icon", args: Icon(ErrorIcon), want: options{icon: ErrorIcon}}, {name: "Icon", args: Icon(ErrorIcon), want: options{icon: ErrorIcon}},
{name: "Icon", args: Icon("error"), want: options{icon: "error"}},
// Message options // Message options
{name: "NoWrap", args: NoWrap(), want: options{noWrap: true}}, {name: "NoWrap", args: NoWrap(), want: options{noWrap: true}},