Files
u-desktop/dialog.go
绝尘 8e7ec8424d 新增: 相册展示模块(左侧幻灯片+进度条+目录选择)
- 左侧固定卡片展示照片幻灯片,淡入淡出切换
- 进度条动画显示当前照片剩余时间
- 设置窗口支持选择图片目录和切换间隔(5/10/15/20/30/60秒)
- Win32 SHBrowseForFolderW 目录选择对话框
- Go 端管理幻灯片状态,按间隔推送照片 data URI
2026-05-26 04:45:58 +08:00

158 lines
4.0 KiB
Go

package main
import (
"fmt"
"unicode/utf16"
"unsafe"
"golang.org/x/sys/windows"
)
var (
comdlg32 = windows.NewLazySystemDLL("comdlg32.dll")
procGetOpenFileNameW = comdlg32.NewProc("GetOpenFileNameW")
procChooseColorW = comdlg32.NewProc("ChooseColorW")
shell32 = windows.NewLazySystemDLL("shell32.dll")
procSHBrowseForFolderW = shell32.NewProc("SHBrowseForFolderW")
procSHGetPathFromIDListW = shell32.NewProc("SHGetPathFromIDListW")
ole32dll = windows.NewLazySystemDLL("ole32.dll")
procCoTaskMemFree = ole32dll.NewProc("CoTaskMemFree")
)
func slicePtr(s interface{}) uintptr {
switch v := s.(type) {
case []uint16:
if len(v) == 0 { return 0 }
return uintptr(unsafe.Pointer(&v[0]))
case []uint32:
if len(v) == 0 { return 0 }
return uintptr(unsafe.Pointer(&v[0]))
}
return 0
}
func openFileDialog(owner uintptr) string {
type openFileName struct {
lStructSize uint32
hwndOwner uintptr
hInstance uintptr
lpstrFilter uintptr
lpstrCustomFilter uintptr
nMaxCustFilter uint32
nFilterIndex uint32
lpstrFile uintptr
nMaxFile uint32
lpstrFileTitle uintptr
nMaxFileTitle uint32
lpstrInitialDir uintptr
lpstrTitle uintptr
Flags uint32
nFileOffset uint16
nFileExtension uint16
lpstrDefExt uintptr
lCustData uintptr
lpfnHook uintptr
lpTemplateName uintptr
pvReserved uintptr
dwReserved uint32
FlagsEx uint32
}
// Filter: "Images\0*.jpg;*.png\0All\0*.*\0\0"
filterStr := "图片文件\x00*.jpg;*.jpeg;*.png;*.bmp;*.webp;*.gif\x00所有文件\x00*.*\x00\x00"
filterUTF16 := utf16.Encode([]rune(filterStr))
titleUTF16 := utf16.Encode([]rune("选择壁纸图片"))
fileBuf := make([]uint16, 260)
ofn := openFileName{
lStructSize: uint32(unsafe.Sizeof(openFileName{})),
hwndOwner: owner,
lpstrFilter: slicePtr(filterUTF16),
lpstrFile: slicePtr(fileBuf),
nMaxFile: 260,
lpstrTitle: slicePtr(titleUTF16),
Flags: 0x00001000 | 0x00000800 | 0x00000004,
}
ret, _, _ := procGetOpenFileNameW.Call(uintptr(unsafe.Pointer(&ofn)))
if ret == 0 {
return ""
}
return windows.UTF16ToString(fileBuf)
}
func colorPickerDialog(owner uintptr, initialColor string) string {
type chooseColor struct {
lStructSize uint32
hwndOwner uintptr
hInstance uintptr
rgbResult uint32
lpCustColors uintptr
Flags uint32
lCustData uintptr
lpfnHook uintptr
lpTemplateName uintptr
}
custColors := make([]uint32, 16)
var initRGB uint32
if len(initialColor) > 4 && initialColor[0] == '#' {
var r, g, b uint32
fmt.Sscanf(initialColor[1:], "%02x%02x%02x", &r, &g, &b)
initRGB = r | (g << 8) | (b << 16)
}
cc := chooseColor{
lStructSize: uint32(unsafe.Sizeof(chooseColor{})),
hwndOwner: owner,
rgbResult: initRGB,
lpCustColors: slicePtr(custColors),
Flags: 0x00000002,
}
ret, _, _ := procChooseColorW.Call(uintptr(unsafe.Pointer(&cc)))
if ret == 0 {
return ""
}
r := cc.rgbResult & 0xFF
g := (cc.rgbResult >> 8) & 0xFF
b := (cc.rgbResult >> 16) & 0xFF
return fmt.Sprintf("#%02x%02x%02x", r, g, b)
}
func browseForFolderDialog(owner uintptr) string {
title, _ := windows.UTF16PtrFromString("选择图片目录")
var displayName [260]uint16
bi := struct {
HwndOwner uintptr
PidlRoot uintptr
PszDisplayName uintptr
LpszTitle uintptr
UlFlags uint32
LpFn uintptr
LParam uintptr
IImage int32
}{
HwndOwner: owner,
PszDisplayName: uintptr(unsafe.Pointer(&displayName[0])),
LpszTitle: uintptr(unsafe.Pointer(title)),
UlFlags: 0x00000001 | 0x00000040,
}
pidl, _, _ := procSHBrowseForFolderW.Call(uintptr(unsafe.Pointer(&bi)))
if pidl == 0 {
return ""
}
defer procCoTaskMemFree.Call(pidl)
var path [260]uint16
procSHGetPathFromIDListW.Call(pidl, uintptr(unsafe.Pointer(&path[0])))
return windows.UTF16ToString(path[:])
}