Folder selection improvements, refactoring (windows).
This commit is contained in:
parent
58dae10a83
commit
f68fa5b0ba
5 changed files with 89 additions and 74 deletions
|
@ -1,7 +1,6 @@
|
|||
package zenity
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
|
@ -13,7 +12,6 @@ import (
|
|||
var (
|
||||
getOpenFileName = comdlg32.NewProc("GetOpenFileNameW")
|
||||
getSaveFileName = comdlg32.NewProc("GetSaveFileNameW")
|
||||
commDlgExtendedError = comdlg32.NewProc("CommDlgExtendedError")
|
||||
shBrowseForFolder = shell32.NewProc("SHBrowseForFolderW")
|
||||
shGetPathFromIDListEx = shell32.NewProc("SHGetPathFromIDListEx")
|
||||
shCreateItemFromParsingName = shell32.NewProc("SHCreateItemFromParsingName")
|
||||
|
@ -175,7 +173,7 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
|
|||
_CLSID_FileOpenDialog, 0, 0x17, // CLSCTX_ALL
|
||||
_IID_IFileOpenDialog, uintptr(unsafe.Pointer(&dialog)))
|
||||
if int32(hr) < 0 {
|
||||
return browseForFolder(opts.title)
|
||||
return browseForFolder(opts)
|
||||
}
|
||||
defer dialog.Call(dialog.vtbl.Release)
|
||||
|
||||
|
@ -267,12 +265,22 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
|
|||
return
|
||||
}
|
||||
|
||||
func browseForFolder(title string) (string, []string, error) {
|
||||
func browseForFolder(opts options) (string, []string, error) {
|
||||
var args _BROWSEINFO
|
||||
args.Flags = 0x1 // BIF_RETURNONLYFSDIRS
|
||||
|
||||
if title != "" {
|
||||
args.Title = syscall.StringToUTF16Ptr(title)
|
||||
if opts.title != "" {
|
||||
args.Title = syscall.StringToUTF16Ptr(opts.title)
|
||||
}
|
||||
if opts.filename != "" {
|
||||
ptr := syscall.StringToUTF16Ptr(opts.filename)
|
||||
args.LParam = uintptr(unsafe.Pointer(ptr))
|
||||
args.CallbackFunc = syscall.NewCallback(func(hwnd uintptr, msg uint32, lparam, data uintptr) uintptr {
|
||||
if msg == 1 { // BFFM_INITIALIZED
|
||||
sendMessage.Call(hwnd, 1024+103 /* BFFM_SETSELECTIONW */, 1 /* TRUE */, data)
|
||||
}
|
||||
return 0
|
||||
})
|
||||
}
|
||||
|
||||
ptr, _, _ := shBrowseForFolder.Call(uintptr(unsafe.Pointer(&args)))
|
||||
|
@ -322,15 +330,6 @@ func windowsFilters(filters []FileFilter) []uint16 {
|
|||
return res
|
||||
}
|
||||
|
||||
func commDlgError() error {
|
||||
n, _, _ := commDlgExtendedError.Call()
|
||||
if n == 0 {
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("Common Dialog error: %x", n)
|
||||
}
|
||||
}
|
||||
|
||||
type _OPENFILENAME struct {
|
||||
StructSize uint32
|
||||
Owner uintptr
|
||||
|
@ -378,23 +377,6 @@ var (
|
|||
_CLSID_FileOpenDialog = uuid("\x9c\x5a\x1c\xdc\x8a\xe8\xde\x4d\xa5\xa1\x60\xf8\x2a\x20\xae\xf7")
|
||||
)
|
||||
|
||||
type _COMObject struct{}
|
||||
|
||||
func (o *_COMObject) Call(trap uintptr, a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
||||
self := uintptr(unsafe.Pointer(o))
|
||||
nargs := uintptr(len(a))
|
||||
switch nargs {
|
||||
case 0:
|
||||
return syscall.Syscall(trap, nargs+1, self, 0, 0)
|
||||
case 1:
|
||||
return syscall.Syscall(trap, nargs+1, self, a[0], 0)
|
||||
case 2:
|
||||
return syscall.Syscall(trap, nargs+1, self, a[0], a[1])
|
||||
default:
|
||||
panic("COM call with too many arguments.")
|
||||
}
|
||||
}
|
||||
|
||||
type _IFileOpenDialog struct {
|
||||
_COMObject
|
||||
vtbl *_IFileOpenDialogVtbl
|
||||
|
@ -467,9 +449,3 @@ type _IShellItemArrayVtbl struct {
|
|||
GetItemAt uintptr
|
||||
EnumItems uintptr
|
||||
}
|
||||
|
||||
type _IUnknownVtbl struct {
|
||||
QueryInterface uintptr
|
||||
AddRef uintptr
|
||||
Release uintptr
|
||||
}
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package zenity
|
||||
|
||||
import "syscall"
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
comdlg32 = syscall.NewLazyDLL("comdlg32.dll")
|
||||
|
@ -9,6 +13,8 @@ var (
|
|||
shell32 = syscall.NewLazyDLL("shell32.dll")
|
||||
user32 = syscall.NewLazyDLL("user32.dll")
|
||||
|
||||
commDlgExtendedError = comdlg32.NewProc("CommDlgExtendedError")
|
||||
|
||||
getCurrentThreadId = kernel32.NewProc("GetCurrentThreadId")
|
||||
|
||||
coInitializeEx = ole32.NewProc("CoInitializeEx")
|
||||
|
@ -16,6 +22,7 @@ var (
|
|||
coCreateInstance = ole32.NewProc("CoCreateInstance")
|
||||
coTaskMemFree = ole32.NewProc("CoTaskMemFree")
|
||||
|
||||
sendMessage = user32.NewProc("SendMessageW")
|
||||
getClassName = user32.NewProc("GetClassNameA")
|
||||
setWindowsHookEx = user32.NewProc("SetWindowsHookExW")
|
||||
unhookWindowsHookEx = user32.NewProc("UnhookWindowsHookEx")
|
||||
|
@ -25,6 +32,15 @@ var (
|
|||
setWindowText = user32.NewProc("SetWindowTextW")
|
||||
)
|
||||
|
||||
func commDlgError() error {
|
||||
n, _, _ := commDlgExtendedError.Call()
|
||||
if n == 0 {
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("Common Dialog error: %x", n)
|
||||
}
|
||||
}
|
||||
|
||||
type _CWPRETSTRUCT struct {
|
||||
Result uintptr
|
||||
LParam uintptr
|
||||
|
@ -32,3 +48,26 @@ type _CWPRETSTRUCT struct {
|
|||
Message uint32
|
||||
HWnd uintptr
|
||||
}
|
||||
|
||||
type _COMObject struct{}
|
||||
|
||||
func (o *_COMObject) Call(trap uintptr, a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
||||
self := uintptr(unsafe.Pointer(o))
|
||||
nargs := uintptr(len(a))
|
||||
switch nargs {
|
||||
case 0:
|
||||
return syscall.Syscall(trap, nargs+1, self, 0, 0)
|
||||
case 1:
|
||||
return syscall.Syscall(trap, nargs+1, self, a[0], 0)
|
||||
case 2:
|
||||
return syscall.Syscall(trap, nargs+1, self, a[0], a[1])
|
||||
default:
|
||||
panic("COM call with too many arguments.")
|
||||
}
|
||||
}
|
||||
|
||||
type _IUnknownVtbl struct {
|
||||
QueryInterface uintptr
|
||||
AddRef uintptr
|
||||
Release uintptr
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"github.com/ncruces/zenity/internal/osa"
|
||||
)
|
||||
|
||||
func Error(text string, options ...Option) (bool, error) {
|
||||
func Question(text string, options ...Option) (bool, error) {
|
||||
return message(0, text, options)
|
||||
}
|
||||
|
||||
|
@ -14,18 +14,18 @@ func Info(text string, options ...Option) (bool, error) {
|
|||
return message(1, text, options)
|
||||
}
|
||||
|
||||
func Question(text string, options ...Option) (bool, error) {
|
||||
func Warning(text string, options ...Option) (bool, error) {
|
||||
return message(2, text, options)
|
||||
}
|
||||
|
||||
func Warning(text string, options ...Option) (bool, error) {
|
||||
func Error(text string, options ...Option) (bool, error) {
|
||||
return message(3, text, options)
|
||||
}
|
||||
|
||||
func message(typ int, text string, options []Option) (bool, error) {
|
||||
opts := optsParse(options)
|
||||
data := osa.Msg{Text: text}
|
||||
dialog := typ == 2 || opts.icon != 0
|
||||
dialog := typ == 0 || opts.icon != 0
|
||||
|
||||
if dialog {
|
||||
data.Operation = "displayDialog"
|
||||
|
@ -47,16 +47,16 @@ func message(typ int, text string, options []Option) (bool, error) {
|
|||
}
|
||||
|
||||
switch typ {
|
||||
case 0:
|
||||
data.As = "critical"
|
||||
case 1:
|
||||
data.As = "informational"
|
||||
case 3:
|
||||
case 2:
|
||||
data.As = "warning"
|
||||
case 3:
|
||||
data.As = "critical"
|
||||
}
|
||||
}
|
||||
|
||||
if typ != 2 {
|
||||
if typ != 0 {
|
||||
if dialog {
|
||||
opts.ok = "OK"
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ func message(typ int, text string, options []Option) (bool, error) {
|
|||
if opts.cancel == "" {
|
||||
opts.cancel = "Cancel"
|
||||
}
|
||||
if typ == 2 {
|
||||
if typ == 0 {
|
||||
if opts.extra == "" {
|
||||
data.Buttons = []string{opts.cancel, opts.ok}
|
||||
data.Default = 2
|
||||
|
|
36
msg_unix.go
36
msg_unix.go
|
@ -8,24 +8,6 @@ import (
|
|||
"github.com/ncruces/zenity/internal/zen"
|
||||
)
|
||||
|
||||
// Display error dialog.
|
||||
//
|
||||
// Returns true on OK, false on dismiss, or ErrExtraButton.
|
||||
//
|
||||
// Valid options: Title, Icon, OKLabel, ExtraButton, NoWrap, Ellipsize.
|
||||
func Error(text string, options ...Option) (bool, error) {
|
||||
return message("--error", text, options)
|
||||
}
|
||||
|
||||
// Display info dialog.
|
||||
//
|
||||
// Returns true on OK, false on dismiss, or ErrExtraButton.
|
||||
//
|
||||
// Valid options: Title, Icon, OKLabel, ExtraButton, NoWrap, Ellipsize.
|
||||
func Info(text string, options ...Option) (bool, error) {
|
||||
return message("--info", text, options)
|
||||
}
|
||||
|
||||
// Display question dialog.
|
||||
//
|
||||
// Returns true on OK, false on Cancel, or ErrExtraButton.
|
||||
|
@ -36,6 +18,15 @@ func Question(text string, options ...Option) (bool, error) {
|
|||
return message("--question", text, options)
|
||||
}
|
||||
|
||||
// Display info dialog.
|
||||
//
|
||||
// Returns true on OK, false on dismiss, or ErrExtraButton.
|
||||
//
|
||||
// Valid options: Title, Icon, OKLabel, ExtraButton, NoWrap, Ellipsize.
|
||||
func Info(text string, options ...Option) (bool, error) {
|
||||
return message("--info", text, options)
|
||||
}
|
||||
|
||||
// Display warning dialog.
|
||||
//
|
||||
// Returns true on OK, false on dismiss, or ErrExtraButton.
|
||||
|
@ -45,6 +36,15 @@ func Warning(text string, options ...Option) (bool, error) {
|
|||
return message("--warning", text, options)
|
||||
}
|
||||
|
||||
// Display error dialog.
|
||||
//
|
||||
// Returns true on OK, false on dismiss, or ErrExtraButton.
|
||||
//
|
||||
// Valid options: Title, Icon, OKLabel, ExtraButton, NoWrap, Ellipsize.
|
||||
func Error(text string, options ...Option) (bool, error) {
|
||||
return message("--error", text, options)
|
||||
}
|
||||
|
||||
func message(arg, text string, options []Option) (bool, error) {
|
||||
opts := optsParse(options)
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ var (
|
|||
messageBox = user32.NewProc("MessageBoxW")
|
||||
)
|
||||
|
||||
func Error(text string, options ...Option) (bool, error) {
|
||||
func Question(text string, options ...Option) (bool, error) {
|
||||
return message(0, text, options)
|
||||
}
|
||||
|
||||
|
@ -18,11 +18,11 @@ func Info(text string, options ...Option) (bool, error) {
|
|||
return message(1, text, options)
|
||||
}
|
||||
|
||||
func Question(text string, options ...Option) (bool, error) {
|
||||
func Warning(text string, options ...Option) (bool, error) {
|
||||
return message(2, text, options)
|
||||
}
|
||||
|
||||
func Warning(text string, options ...Option) (bool, error) {
|
||||
func Error(text string, options ...Option) (bool, error) {
|
||||
return message(3, text, options)
|
||||
}
|
||||
|
||||
|
@ -32,9 +32,9 @@ func message(typ int, text string, options []Option) (bool, error) {
|
|||
var flags, caption uintptr
|
||||
|
||||
switch {
|
||||
case typ == 2 && opts.extra != "":
|
||||
case typ == 0 && opts.extra != "":
|
||||
flags |= 0x3 // MB_YESNOCANCEL
|
||||
case typ == 2 || opts.extra != "":
|
||||
case typ == 0 || opts.extra != "":
|
||||
flags |= 0x1 // MB_OKCANCEL
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,7 @@ func message(typ int, text string, options []Option) (bool, error) {
|
|||
flags |= 0x40 // MB_ICONINFORMATION
|
||||
}
|
||||
|
||||
if typ == 2 && opts.defcancel {
|
||||
if typ == 0 && opts.defcancel {
|
||||
if opts.extra == "" {
|
||||
flags |= 0x100 // MB_DEFBUTTON2
|
||||
} else {
|
||||
|
@ -79,7 +79,7 @@ func message(typ int, text string, options []Option) (bool, error) {
|
|||
if n == 0 {
|
||||
return false, err
|
||||
}
|
||||
if n == 7 || n == 2 && typ != 2 { // IDNO
|
||||
if n == 7 || n == 2 && typ != 0 { // IDNO
|
||||
return false, ErrExtraButton
|
||||
}
|
||||
if n == 1 || n == 6 { // IDOK, IDYES
|
||||
|
@ -107,7 +107,7 @@ func hookMessageLabels(typ int, opts options) (hook uintptr, err error) {
|
|||
case 1, 6: // IDOK, IDYES
|
||||
text = opts.ok
|
||||
case 2: // IDCANCEL
|
||||
if typ == 2 {
|
||||
if typ == 0 {
|
||||
text = opts.cancel
|
||||
} else if opts.extra != "" {
|
||||
text = opts.extra
|
||||
|
|
Loading…
Reference in a new issue