erm/vendor/github.com/lxn/walk/imagelist.go
2021-07-30 23:29:20 +01:00

269 lines
6.2 KiB
Go

// Copyright 2010 The Walk Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
package walk
import (
"syscall"
"unsafe"
"github.com/lxn/win"
)
type ImageList struct {
hIml win.HIMAGELIST
dpi int
maskColor Color
imageSize96dpi Size
colorMaskedBitmap2Index map[*Bitmap]int
bitmapMaskedBitmap2Index map[bitmapMaskedBitmap]int
icon2Index map[*Icon]int32
}
type bitmapMaskedBitmap struct {
bitmap *Bitmap
mask *Bitmap
}
// NewImageList creates an empty image list at 96dpi. imageSize parameter is specified in 1/96"
// units.
//
// Deprecated: Newer applications should use NewImageListForDPI.
func NewImageList(imageSize Size, maskColor Color) (*ImageList, error) {
return NewImageListForDPI(SizeFrom96DPI(imageSize, 96), maskColor, 96)
}
// NewImageListForDPI creates an empty image list for image size at given DPI. imageSize is
// specified in native pixels.
func NewImageListForDPI(imageSize Size, maskColor Color, dpi int) (*ImageList, error) {
hIml := win.ImageList_Create(
int32(imageSize.Width),
int32(imageSize.Height),
win.ILC_MASK|win.ILC_COLOR32,
8,
8)
if hIml == 0 {
return nil, newError("ImageList_Create failed")
}
return &ImageList{
hIml: hIml,
dpi: dpi,
maskColor: maskColor,
imageSize96dpi: SizeTo96DPI(imageSize, dpi),
colorMaskedBitmap2Index: make(map[*Bitmap]int),
bitmapMaskedBitmap2Index: make(map[bitmapMaskedBitmap]int),
icon2Index: make(map[*Icon]int32),
}, nil
}
func (il *ImageList) Handle() win.HIMAGELIST {
return il.hIml
}
func (il *ImageList) Add(bitmap, maskBitmap *Bitmap) (int, error) {
if bitmap == nil {
return 0, newError("bitmap cannot be nil")
}
key := bitmapMaskedBitmap{bitmap: bitmap, mask: maskBitmap}
if index, ok := il.bitmapMaskedBitmap2Index[key]; ok {
return index, nil
}
var maskHandle win.HBITMAP
if maskBitmap != nil {
maskHandle = maskBitmap.handle()
}
index := int(win.ImageList_Add(il.hIml, bitmap.handle(), maskHandle))
if index == -1 {
return 0, newError("ImageList_Add failed")
}
il.bitmapMaskedBitmap2Index[key] = index
return index, nil
}
func (il *ImageList) AddMasked(bitmap *Bitmap) (int32, error) {
if bitmap == nil {
return 0, newError("bitmap cannot be nil")
}
if index, ok := il.colorMaskedBitmap2Index[bitmap]; ok {
return int32(index), nil
}
index := win.ImageList_AddMasked(
il.hIml,
bitmap.handle(),
win.COLORREF(il.maskColor))
if index == -1 {
return 0, newError("ImageList_AddMasked failed")
}
il.colorMaskedBitmap2Index[bitmap] = int(index)
return index, nil
}
func (il *ImageList) AddIcon(icon *Icon) (int32, error) {
if icon == nil {
return 0, newError("icon cannot be nil")
}
if index, ok := il.icon2Index[icon]; ok {
return index, nil
}
index := win.ImageList_ReplaceIcon(il.hIml, -1, icon.handleForDPI(il.dpi))
if index == -1 {
return 0, newError("ImageList_ReplaceIcon failed")
}
il.icon2Index[icon] = index
return index, nil
}
func (il *ImageList) AddImage(image interface{}) (int32, error) {
switch image.(type) {
case ExtractableIcon, *Icon:
icon, err := IconFrom(image, il.dpi)
if err != nil {
return 0, err
}
return il.AddIcon(icon)
default:
bmp, err := BitmapFrom(image, il.dpi)
if err != nil {
return 0, err
}
return il.AddMasked(bmp)
}
}
func (il *ImageList) DrawPixels(canvas *Canvas, index int, bounds Rectangle) error {
if !win.ImageList_DrawEx(il.hIml, int32(index), canvas.hdc, int32(bounds.X), int32(bounds.Y), int32(bounds.Width), int32(bounds.Height), win.CLR_DEFAULT, win.CLR_DEFAULT, win.ILD_NORMAL) {
return newError("ImageList_DrawEx")
}
return nil
}
func (il *ImageList) Dispose() {
if il.hIml != 0 {
win.ImageList_Destroy(il.hIml)
il.hIml = 0
}
}
func (il *ImageList) MaskColor() Color {
return il.maskColor
}
func imageListForImage(image interface{}, dpi int) (hIml win.HIMAGELIST, isSysIml bool, err error) {
if name, ok := image.(string); ok {
if img, err := Resources.Image(name); err == nil {
image = img
}
}
if filePath, ok := image.(string); ok {
_, hIml = iconIndexAndHImlForFilePath(filePath)
isSysIml = hIml != 0
} else {
w := int32(win.GetSystemMetricsForDpi(win.SM_CXSMICON, uint32(dpi)))
h := int32(win.GetSystemMetricsForDpi(win.SM_CYSMICON, uint32(dpi)))
hIml = win.ImageList_Create(w, h, win.ILC_MASK|win.ILC_COLOR32, 8, 8)
if hIml == 0 {
return 0, false, newError("ImageList_Create failed")
}
}
return
}
func iconIndexAndHImlForFilePath(filePath string) (int32, win.HIMAGELIST) {
var shfi win.SHFILEINFO
if hIml := win.HIMAGELIST(win.SHGetFileInfo(
syscall.StringToUTF16Ptr(filePath),
0,
&shfi,
uint32(unsafe.Sizeof(shfi)),
win.SHGFI_SYSICONINDEX|win.SHGFI_SMALLICON)); hIml != 0 {
return shfi.IIcon, hIml
}
return -1, 0
}
func imageIndexMaybeAdd(image interface{}, hIml win.HIMAGELIST, isSysIml bool, imageUintptr2Index map[uintptr]int32, filePath2IconIndex map[string]int32, dpi int) int32 {
if !isSysIml {
return imageIndexAddIfNotExists(image, hIml, imageUintptr2Index, dpi)
} else if filePath, ok := image.(string); ok {
if iIcon, ok := filePath2IconIndex[filePath]; ok {
return iIcon
}
if iIcon, _ := iconIndexAndHImlForFilePath(filePath); iIcon != -1 {
filePath2IconIndex[filePath] = iIcon
return iIcon
}
}
return -1
}
func imageIndexAddIfNotExists(image interface{}, hIml win.HIMAGELIST, imageUintptr2Index map[uintptr]int32, dpi int) int32 {
imageIndex := int32(-1)
if image != nil {
if name, ok := image.(string); ok {
image, _ = Resources.Image(name)
}
var ptr uintptr
switch img := image.(type) {
case *Bitmap:
ptr = uintptr(unsafe.Pointer(img))
case *Icon:
ptr = uintptr(unsafe.Pointer(img))
}
if ptr == 0 {
return -1
}
if imageIndex, ok := imageUintptr2Index[ptr]; ok {
return imageIndex
}
switch img := image.(type) {
case *Bitmap:
imageIndex = win.ImageList_AddMasked(hIml, img.hBmp, 0)
case *Icon:
imageIndex = win.ImageList_ReplaceIcon(hIml, -1, img.handleForDPI(dpi))
}
if imageIndex > -1 {
imageUintptr2Index[ptr] = imageIndex
}
}
return imageIndex
}