Mercurial > projects > dwt-win
view dwt/internal/ImageList.d @ 213:36f5cb12e1a2
Update to SWT 3.4M7
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sat, 17 May 2008 17:34:28 +0200 |
parents | 619faee45ef6 |
children |
line wrap: on
line source
/******************************************************************************* * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Port to the D programming language: * Frank Benoit <benoit@tionex.de> *******************************************************************************/ module dwt.internal.ImageList; import dwt.DWT; import dwt.graphics.Color; import dwt.graphics.Image; import dwt.graphics.ImageData; import dwt.graphics.PaletteData; import dwt.graphics.Point; import dwt.graphics.RGB; import dwt.graphics.Rectangle; import dwt.internal.win32.OS; import dwt.dwthelper.utils; import dwt.dwthelper.System; public class ImageList { HIMAGELIST handle; int style, refCount; Image [] images; public this (int style) { this.style = style; int flags = OS.ILC_MASK; static if (OS.IsWinCE) { flags |= OS.ILC_COLOR; } else { if (OS.COMCTL32_MAJOR >= 6) { flags |= OS.ILC_COLOR32; } else { auto hDC = OS.GetDC (null); auto bits = OS.GetDeviceCaps (hDC, OS.BITSPIXEL); auto planes = OS.GetDeviceCaps (hDC, OS.PLANES); OS.ReleaseDC (null, hDC); int depth = bits * planes; switch (depth) { case 4: flags |= OS.ILC_COLOR4; break; case 8: flags |= OS.ILC_COLOR8; break; case 16: flags |= OS.ILC_COLOR16; break; case 24: flags |= OS.ILC_COLOR24; break; case 32: flags |= OS.ILC_COLOR32; break; default: flags |= OS.ILC_COLOR; break; } } } if ((style & DWT.RIGHT_TO_LEFT) !is 0) flags |= OS.ILC_MIRROR; handle = OS.ImageList_Create (32, 32, flags, 16, 16); images = new Image [4]; } public int add (Image image) { int count = OS.ImageList_GetImageCount (handle); int index = 0; while (index < count) { if (images [index] !is null) { if (images [index].isDisposed ()) images [index] = null; } if (images [index] is null) break; index++; } if (count is 0) { Rectangle rect = image.getBounds (); OS.ImageList_SetIconSize (handle, rect.width, rect.height); } set (index, image, count); if (index is images.length) { Image [] newImages = new Image [images.length + 4]; System.arraycopy (images, 0, newImages, 0, images.length); images = newImages; } images [index] = image; return index; } public int addRef() { return ++refCount; } HBITMAP copyBitmap (HBITMAP hImage, int width, int height) { BITMAP bm; OS.GetObject (hImage, BITMAP.sizeof, &bm); auto hDC = OS.GetDC (null); auto hdc1 = OS.CreateCompatibleDC (hDC); OS.SelectObject (hdc1, hImage); auto hdc2 = OS.CreateCompatibleDC (hDC); /* * Feature in Windows. If a bitmap has a 32-bit depth and any * pixel has an alpha value different than zero, common controls * version 6.0 assumes that the bitmap should be alpha blended. * AlphaBlend() composes the alpha channel of a destination 32-bit * depth image with the alpha channel of the source image. This * may cause opaque images to draw transparently. The fix is * remove the alpha channel of opaque images by down sampling * it to 24-bit depth. */ HBITMAP hBitmap; if (bm.bmBitsPixel is 32 && OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) { BITMAPINFOHEADER bmiHeader; bmiHeader.biSize = BITMAPINFOHEADER.sizeof; bmiHeader.biWidth = width; bmiHeader.biHeight = -height; bmiHeader.biPlanes = 1; bmiHeader.biBitCount = cast(short)24; static if (OS.IsWinCE) bmiHeader.biCompression = OS.BI_BITFIELDS; else bmiHeader.biCompression = OS.BI_RGB; byte[] bmi = new byte[BITMAPINFOHEADER.sizeof + (OS.IsWinCE ? 12 : 0)]; *cast(BITMAPINFOHEADER*)bmi.ptr = bmiHeader; //OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof); /* Set the rgb colors into the bitmap info */ static if (OS.IsWinCE) { int redMask = 0xFF00; int greenMask = 0xFF0000; int blueMask = 0xFF000000; /* big endian */ int offset = BITMAPINFOHEADER.sizeof; bmi[offset] = cast(byte)((redMask & 0xFF000000) >> 24); bmi[offset + 1] = cast(byte)((redMask & 0xFF0000) >> 16); bmi[offset + 2] = cast(byte)((redMask & 0xFF00) >> 8); bmi[offset + 3] = cast(byte)((redMask & 0xFF) >> 0); bmi[offset + 4] = cast(byte)((greenMask & 0xFF000000) >> 24); bmi[offset + 5] = cast(byte)((greenMask & 0xFF0000) >> 16); bmi[offset + 6] = cast(byte)((greenMask & 0xFF00) >> 8); bmi[offset + 7] = cast(byte)((greenMask & 0xFF) >> 0); bmi[offset + 8] = cast(byte)((blueMask & 0xFF000000) >> 24); bmi[offset + 9] = cast(byte)((blueMask & 0xFF0000) >> 16); bmi[offset + 10] = cast(byte)((blueMask & 0xFF00) >> 8); bmi[offset + 11] = cast(byte)((blueMask & 0xFF) >> 0); } void* pBits; hBitmap = OS.CreateDIBSection(null, cast(BITMAPINFO*)bmi.ptr, OS.DIB_RGB_COLORS, &pBits, null, 0); } else { hBitmap = OS.CreateCompatibleBitmap (hDC, width, height); } OS.SelectObject (hdc2, hBitmap); if (width !is bm.bmWidth || height !is bm.bmHeight) { static if (!OS.IsWinCE) OS.SetStretchBltMode(hdc2, OS.COLORONCOLOR); OS.StretchBlt (hdc2, 0, 0, width, height, hdc1, 0, 0, bm.bmWidth, bm.bmHeight, OS.SRCCOPY); } else { OS.BitBlt (hdc2, 0, 0, width, height, hdc1, 0, 0, OS.SRCCOPY); } OS.DeleteDC (hdc1); OS.DeleteDC (hdc2); OS.ReleaseDC (null, hDC); return hBitmap; } HBITMAP copyIcon (HBITMAP hImage, int width, int height) { static if (OS.IsWinCE) DWT.error(DWT.ERROR_NOT_IMPLEMENTED); auto hIcon = OS.CopyImage (hImage, OS.IMAGE_ICON, width, height, 0); return hIcon !is null ? hIcon : hImage; } HBITMAP copyWithAlpha (HBITMAP hBitmap, int background, byte[] alphaData, int destWidth, int destHeight) { BITMAP bm; OS.GetObject (hBitmap, BITMAP.sizeof, &bm); int srcWidth = bm.bmWidth; int srcHeight = bm.bmHeight; /* Create resources */ auto hdc = OS.GetDC (null); auto srcHdc = OS.CreateCompatibleDC (hdc); auto oldSrcBitmap = OS.SelectObject (srcHdc, hBitmap); auto memHdc = OS.CreateCompatibleDC (hdc); BITMAPINFOHEADER bmiHeader; bmiHeader.biSize = BITMAPINFOHEADER.sizeof; bmiHeader.biWidth = srcWidth; bmiHeader.biHeight = -srcHeight; bmiHeader.biPlanes = 1; bmiHeader.biBitCount = 32; bmiHeader.biCompression = OS.BI_RGB; byte [] bmi = new byte[BITMAPINFOHEADER.sizeof]; *cast(BITMAPINFOHEADER*)bmi.ptr = bmiHeader; //OS.MoveMemory (bmi, bmiHeader, BITMAPINFOHEADER.sizeof); void* pBits; auto memDib = OS.CreateDIBSection (null, cast(BITMAPINFO*)bmi.ptr, OS.DIB_RGB_COLORS, &pBits, null, 0); if (memDib is null) DWT.error (DWT.ERROR_NO_HANDLES); auto oldMemBitmap = OS.SelectObject (memHdc, memDib); BITMAP dibBM; OS.GetObject (memDib, BITMAP.sizeof, &dibBM); int sizeInBytes = dibBM.bmWidthBytes * dibBM.bmHeight; /* Get the foreground pixels */ OS.BitBlt (memHdc, 0, 0, srcWidth, srcHeight, srcHdc, 0, 0, OS.SRCCOPY); byte[] srcData = (cast(byte*)dibBM.bmBits)[ 0 .. sizeInBytes].dup; //OS.MoveMemory (srcData, dibBM.bmBits, sizeInBytes); /* Merge the alpha channel in place */ if (alphaData !is null) { int spinc = dibBM.bmWidthBytes - srcWidth * 4; int ap = 0, sp = 3; for (int y = 0; y < srcHeight; ++y) { for (int x = 0; x < srcWidth; ++x) { srcData [sp] = alphaData [ap++]; sp += 4; } sp += spinc; } } else { byte transRed = cast(byte)(background & 0xFF); byte transGreen = cast(byte)((background >> 8) & 0xFF); byte transBlue = cast(byte)((background >> 16) & 0xFF); final int spinc = dibBM.bmWidthBytes - srcWidth * 4; int sp = 3; for (int y = 0; y < srcHeight; ++y) { for (int x = 0; x < srcWidth; ++x) { srcData [sp] = (srcData[sp-1] is transRed && srcData[sp-2] is transGreen && srcData[sp-3] is transBlue) ? 0 : cast(byte)255; sp += 4; } sp += spinc; } } (cast(byte*)dibBM.bmBits)[ 0 .. sizeInBytes] = srcData; //OS.MoveMemory (dibBM.bmBits, srcData, sizeInBytes); /* Stretch and free resources */ if (srcWidth !is destWidth || srcHeight !is destHeight) { BITMAPINFOHEADER bmiHeader2; bmiHeader2.biSize = BITMAPINFOHEADER.sizeof; bmiHeader2.biWidth = destWidth; bmiHeader2.biHeight = -destHeight; bmiHeader2.biPlanes = 1; bmiHeader2.biBitCount = 32; bmiHeader2.biCompression = OS.BI_RGB; byte [] bmi2 = new byte[BITMAPINFOHEADER.sizeof]; *cast(BITMAPINFOHEADER*)bmi2.ptr = bmiHeader2; //OS.MoveMemory (bmi2, bmiHeader2, BITMAPINFOHEADER.sizeof); void* pBits2; auto memDib2 = OS.CreateDIBSection (null, cast(BITMAPINFO*)bmi2.ptr, OS.DIB_RGB_COLORS, &pBits2, null, 0); auto memHdc2 = OS.CreateCompatibleDC (hdc); auto oldMemBitmap2 = OS.SelectObject (memHdc2, memDib2); static if (!OS.IsWinCE) OS.SetStretchBltMode(memHdc2, OS.COLORONCOLOR); OS.StretchBlt (memHdc2, 0, 0, destWidth, destHeight, memHdc, 0, 0, srcWidth, srcHeight, OS.SRCCOPY); OS.SelectObject (memHdc2, oldMemBitmap2); OS.DeleteDC (memHdc2); OS.SelectObject (memHdc, oldMemBitmap); OS.DeleteDC (memHdc); OS.DeleteObject (memDib); memDib = memDib2; } else { OS.SelectObject (memHdc, oldMemBitmap); OS.DeleteDC (memHdc); } OS.SelectObject (srcHdc, oldSrcBitmap); OS.DeleteDC (srcHdc); OS.ReleaseDC (null, hdc); return memDib; } HBITMAP createMaskFromAlpha (ImageData data, int destWidth, int destHeight) { int srcWidth = data.width; int srcHeight = data.height; ImageData mask = ImageData.internal_new (srcWidth, srcHeight, 1, new PaletteData([new RGB (0, 0, 0), new RGB (0xff, 0xff, 0xff)]), 2, null, 1, null, null, -1, -1, -1, 0, 0, 0, 0); int ap = 0; for (int y = 0; y < mask.height; y++) { for (int x = 0; x < mask.width; x++) { mask.setPixel (x, y, (data.alphaData [ap++] & 0xff) <= 127 ? 1 : 0); } } auto hMask = OS.CreateBitmap (srcWidth, srcHeight, 1, 1, mask.data.ptr); if (srcWidth !is destWidth || srcHeight !is destHeight) { auto hdc = OS.GetDC (null); auto hdc1 = OS.CreateCompatibleDC (hdc); OS.SelectObject (hdc1, hMask); auto hdc2 = OS.CreateCompatibleDC (hdc); auto hMask2 = OS.CreateBitmap (destWidth, destHeight, 1, 1, null); OS.SelectObject (hdc2, hMask2); static if (!OS.IsWinCE) OS.SetStretchBltMode(hdc2, OS.COLORONCOLOR); OS.StretchBlt (hdc2, 0, 0, destWidth, destHeight, hdc1, 0, 0, srcWidth, srcHeight, OS.SRCCOPY); OS.DeleteDC (hdc1); OS.DeleteDC (hdc2); OS.ReleaseDC (null, hdc); OS.DeleteObject(hMask); hMask = hMask2; } return hMask; } HBITMAP createMask (HBITMAP hBitmap, int destWidth, int destHeight, int background, int transparentPixel) { BITMAP bm; OS.GetObject (hBitmap, BITMAP.sizeof, &bm); int srcWidth = bm.bmWidth; int srcHeight = bm.bmHeight; auto hMask = OS.CreateBitmap (destWidth, destHeight, 1, 1, null); auto hDC = OS.GetDC (null); auto hdc1 = OS.CreateCompatibleDC (hDC); if (background !is -1) { OS.SelectObject (hdc1, hBitmap); /* * If the image has a palette with multiple entries having * the same color and one of those entries is the transparentPixel, * only the first entry becomes transparent. To avoid this * problem, temporarily change the image palette to a palette * where the transparentPixel is white and everything else is * black. */ bool isDib = bm.bmBits !is null; byte[] originalColors = null; if (!OS.IsWinCE && transparentPixel !is -1 && isDib && bm.bmBitsPixel <= 8) { int maxColors = 1 << bm.bmBitsPixel; byte[] oldColors = new byte[maxColors * 4]; OS.GetDIBColorTable(hdc1, 0, maxColors, cast(RGBQUAD*)oldColors.ptr); int offset = transparentPixel * 4; byte[] newColors = new byte[oldColors.length]; newColors[offset] = cast(byte)0xFF; newColors[offset+1] = cast(byte)0xFF; newColors[offset+2] = cast(byte)0xFF; OS.SetDIBColorTable(hdc1, 0, maxColors, cast(RGBQUAD*)newColors.ptr); originalColors = oldColors; OS.SetBkColor (hdc1, 0xFFFFFF); } else { OS.SetBkColor (hdc1, background); } auto hdc2 = OS.CreateCompatibleDC (hDC); OS.SelectObject (hdc2, hMask); if (destWidth !is srcWidth || destHeight !is srcHeight) { static if (!OS.IsWinCE) OS.SetStretchBltMode (hdc2, OS.COLORONCOLOR); OS.StretchBlt (hdc2, 0, 0, destWidth, destHeight, hdc1, 0, 0, srcWidth, srcHeight, OS.SRCCOPY); } else { OS.BitBlt (hdc2, 0, 0, destWidth, destHeight, hdc1, 0, 0, OS.SRCCOPY); } OS.DeleteDC (hdc2); /* Put back the original palette */ if (originalColors !is null) OS.SetDIBColorTable(hdc1, 0, 1 << bm.bmBitsPixel, cast(RGBQUAD*)originalColors.ptr); } else { auto hOldBitmap = OS.SelectObject (hdc1, hMask); OS.PatBlt (hdc1, 0, 0, destWidth, destHeight, OS.BLACKNESS); OS.SelectObject (hdc1, hOldBitmap); } OS.ReleaseDC (null, hDC); OS.DeleteDC (hdc1); return hMask; } public void dispose () { if (handle !is null) OS.ImageList_Destroy (handle); handle = null; images = null; } public Image get (int index) { return images [index]; } public int getStyle () { return style; } public HIMAGELIST getHandle () { return handle; } public Point getImageSize() { int cx, cy; OS.ImageList_GetIconSize (handle, &cx, &cy); return new Point (cx, cy); } public int indexOf (Image image) { int count = OS.ImageList_GetImageCount (handle); for (int i=0; i<count; i++) { if (images [i] !is null) { if (images [i].isDisposed ()) images [i] = null; if (images [i] !is null && images [i]==/*eq*/image) return i; } } return -1; } public void put (int index, Image image) { int count = OS.ImageList_GetImageCount (handle); if (!(0 <= index && index < count)) return; if (image !is null) set(index, image, count); images [index] = image; } public void remove (int index) { int count = OS.ImageList_GetImageCount (handle); if (!(0 <= index && index < count)) return; OS.ImageList_Remove (handle, index); System.arraycopy (images, index + 1, images, index, --count - index); images [index] = null; } public int removeRef() { return --refCount; } void set (int index, Image image, int count) { auto hImage = image.handle; int cx , cy ; OS.ImageList_GetIconSize (handle, &cx, &cy); switch (image.type) { case DWT.BITMAP: { /* * Note that the image size has to match the image list icon size. */ HBITMAP hBitmap, hMask; ImageData data = image.getImageData (); switch (data.getTransparencyType ()) { case DWT.TRANSPARENCY_ALPHA: if (OS.COMCTL32_MAJOR >= 6) { hBitmap = copyWithAlpha (hImage, -1, data.alphaData, cx, cy); } else { hBitmap = copyBitmap (hImage, cx, cy); hMask = createMaskFromAlpha (data, cx, cy); } break; case DWT.TRANSPARENCY_PIXEL: int background = -1; Color color = image.getBackground (); if (color !is null) background = color.handle; hBitmap = copyBitmap (hImage, cx, cy); hMask = createMask (hImage, cx, cy, background, data.transparentPixel); break; case DWT.TRANSPARENCY_NONE: default: hBitmap = copyBitmap (hImage, cx, cy); if (index !is count) hMask = createMask (hImage, cx, cy, -1, -1); break; } if (index is count) { OS.ImageList_Add (handle, hBitmap, hMask); } else { /* Note that the mask must always be replaced even for TRANSPARENCY_NONE */ OS.ImageList_Replace (handle, index, hBitmap, hMask); } if (hMask !is null) OS.DeleteObject (hMask); if (hBitmap !is hImage) OS.DeleteObject (hBitmap); break; } case DWT.ICON: { static if (OS.IsWinCE) { OS.ImageList_ReplaceIcon (handle, index is count ? -1 : index, hImage); } else { auto hIcon = copyIcon (hImage, cx, cy); OS.ImageList_ReplaceIcon (handle, index is count ? -1 : index, hIcon); OS.DestroyIcon (hIcon); } break; } default: } } public int size () { int result = 0; int count = OS.ImageList_GetImageCount (handle); for (int i=0; i<count; i++) { if (images [i] !is null) { if (images [i].isDisposed ()) images [i] = null; if (images [i] !is null) result++; } } return result; } }