269 lines
6.2 KiB
Go
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
|
|
}
|