imagelist.c
来自「一个类似windows」· C语言 代码 · 共 2,271 行 · 第 1/5 页
C
2,271 行
/*
* ImageList implementation
*
* Copyright 1998 Eric Kohl
* Copyright 2000 Jason Mawdsley
* Copyright 2001, 2004 Michael Stefaniuc
* Copyright 2001 Charles Loep for CodeWeavers
* Copyright 2002 Dimitrie O. Paun
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* NOTE
*
* This code was audited for completeness against the documented features
* of Comctl32.dll version 6.0 on Sep. 12, 2002, by Dimitrie O. Paun.
*
* Unless otherwise noted, we believe this code to be complete, as per
* the specification mentioned above.
* If you discover missing features, or bugs, please note them below.
*
* TODO:
* - Add support for ILD_PRESERVEALPHA, ILD_SCALE, ILD_DPISCALE
* - Add support for ILS_GLOW, ILS_SHADOW, ILS_SATURATE, ILS_ALPHA
* - Thread-safe locking
*/
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#define COBJMACROS
#include "winerror.h"
#include "windef.h"
#include "winbase.h"
#include "objbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "commctrl.h"
#include "comctl32.h"
#include "imagelist.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
#define MAX_OVERLAYIMAGE 15
/* internal image list data used for Drag & Drop operations */
typedef struct
{
HWND hwnd;
HIMAGELIST himl;
/* position of the drag image relative to the window */
INT x;
INT y;
/* offset of the hotspot relative to the origin of the image */
INT dxHotspot;
INT dyHotspot;
/* is the drag image visible */
BOOL bShow;
/* saved background */
HBITMAP hbmBg;
} INTERNALDRAG;
static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0 };
static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT width, UINT height);
static inline BOOL is_valid(HIMAGELIST himl)
{
return himl && himl->magic == IMAGELIST_MAGIC;
}
/*************************************************************************
* IMAGELIST_InternalExpandBitmaps [Internal]
*
* Expands the bitmaps of an image list by the given number of images.
*
* PARAMS
* himl [I] handle to image list
* nImageCount [I] number of images to add
*
* RETURNS
* nothing
*
* NOTES
* This function CANNOT be used to reduce the number of images.
*/
static void
IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
{
HDC hdcBitmap;
HBITMAP hbmNewBitmap, hbmNull;
INT nNewWidth, nNewCount;
if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
&& (himl->cy >= cy))
return;
if (cy == 0) cy = himl->cy;
nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
nNewWidth = nNewCount * himl->cx;
TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
hdcBitmap = CreateCompatibleDC (0);
hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewWidth, cy);
if (hbmNewBitmap == 0)
ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
if(himl->cCurImage)
{
hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
himl->hdcImage, 0, 0, SRCCOPY);
SelectObject (hdcBitmap, hbmNull);
}
SelectObject (himl->hdcImage, hbmNewBitmap);
DeleteObject (himl->hbmImage);
himl->hbmImage = hbmNewBitmap;
if (himl->flags & ILC_MASK)
{
hbmNewBitmap = CreateBitmap (nNewWidth, cy, 1, 1, NULL);
if (hbmNewBitmap == 0)
ERR("creating new mask bitmap!\n");
if(himl->cCurImage)
{
hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
himl->hdcMask, 0, 0, SRCCOPY);
SelectObject (hdcBitmap, hbmNull);
}
SelectObject (himl->hdcMask, hbmNewBitmap);
DeleteObject (himl->hbmMask);
himl->hbmMask = hbmNewBitmap;
}
himl->cMaxImage = nNewCount;
DeleteDC (hdcBitmap);
}
/*************************************************************************
* ImageList_Add [COMCTL32.@]
*
* Add an image or images to an image list.
*
* PARAMS
* himl [I] handle to image list
* hbmImage [I] handle to image bitmap
* hbmMask [I] handle to mask bitmap
*
* RETURNS
* Success: Index of the first new image.
* Failure: -1
*/
INT WINAPI
ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
{
HDC hdcBitmap;
INT nFirstIndex, nImageCount;
INT nStartX;
BITMAP bmp;
HBITMAP hOldBitmap;
TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
if (!is_valid(himl))
return -1;
GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
nImageCount = bmp.bmWidth / himl->cx;
IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
nStartX = himl->cCurImage * himl->cx;
hdcBitmap = CreateCompatibleDC(0);
hOldBitmap = SelectObject(hdcBitmap, hbmImage);
/* Copy result to the imagelist
*/
BitBlt (himl->hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
hdcBitmap, 0, 0, SRCCOPY);
if(himl->hbmMask)
{
HDC hdcTemp;
HBITMAP hOldBitmapTemp;
hdcTemp = CreateCompatibleDC(0);
hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
BitBlt (himl->hdcMask,
nStartX, 0, bmp.bmWidth, bmp.bmHeight,
hdcTemp,
0, 0,
SRCCOPY);
SelectObject(hdcTemp, hOldBitmapTemp);
DeleteDC(hdcTemp);
/* Remove the background from the image
*/
BitBlt (himl->hdcImage,
nStartX, 0, bmp.bmWidth, bmp.bmHeight,
himl->hdcMask,
nStartX, 0,
0x220326); /* NOTSRCAND */
}
SelectObject(hdcBitmap, hOldBitmap);
DeleteDC(hdcBitmap);
nFirstIndex = himl->cCurImage;
himl->cCurImage += nImageCount;
return nFirstIndex;
}
/*************************************************************************
* ImageList_AddIcon [COMCTL32.@]
*
* Adds an icon to an image list.
*
* PARAMS
* himl [I] handle to image list
* hIcon [I] handle to icon
*
* RETURNS
* Success: index of the new image
* Failure: -1
*/
#undef ImageList_AddIcon
INT WINAPI ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
{
return ImageList_ReplaceIcon (himl, -1, hIcon);
}
/*************************************************************************
* ImageList_AddMasked [COMCTL32.@]
*
* Adds an image or images to an image list and creates a mask from the
* specified bitmap using the mask color.
*
* PARAMS
* himl [I] handle to image list.
* hBitmap [I] handle to bitmap
* clrMask [I] mask color.
*
* RETURNS
* Success: Index of the first new image.
* Failure: -1
*/
INT WINAPI
ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
{
HDC hdcMask, hdcBitmap;
INT nIndex, nImageCount, nMaskXOffset=0;
BITMAP bmp;
HBITMAP hOldBitmap;
HBITMAP hMaskBitmap=0;
COLORREF bkColor;
TRACE("himl=%p hbitmap=%p clrmask=%lx\n", himl, hBitmap, clrMask);
if (!is_valid(himl))
return -1;
if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
return -1;
if (himl->cx > 0)
nImageCount = bmp.bmWidth / himl->cx;
else
nImageCount = 0;
IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
nIndex = himl->cCurImage;
himl->cCurImage += nImageCount;
hdcBitmap = CreateCompatibleDC(0);
hOldBitmap = SelectObject(hdcBitmap, hBitmap);
if(himl->hbmMask)
{
hdcMask = himl->hdcMask;
nMaskXOffset = nIndex * himl->cx;
}
else
{
/*
Create a temp Mask so we can remove the background of
the Image (Windows does this even if there is no mask)
*/
hdcMask = CreateCompatibleDC(0);
hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
SelectObject(hdcMask, hMaskBitmap);
nMaskXOffset = 0;
}
/* create monochrome image to the mask bitmap */
bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
GetPixel (hdcBitmap, 0, 0);
SetBkColor (hdcBitmap, bkColor);
BitBlt (hdcMask,
nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
hdcBitmap, 0, 0,
SRCCOPY);
SetBkColor(hdcBitmap, RGB(255,255,255));
/*Remove the background from the image
*/
/*
WINDOWS BUG ALERT!!!!!!
The statement below should not be done in common practice
but this is how ImageList_AddMasked works in Windows.
It overwrites the original bitmap passed, this was discovered
by using the same bitmap to iterate the different styles
on windows where it failed (BUT ImageList_Add is OK)
This is here in case some apps rely on this bug
*/
BitBlt(hdcBitmap,
0, 0, bmp.bmWidth, bmp.bmHeight,
hdcMask,
nMaskXOffset, 0,
0x220326); /* NOTSRCAND */
/* Copy result to the imagelist
*/
BitBlt (himl->hdcImage,
nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
hdcBitmap,
0, 0,
SRCCOPY);
/* Clean up
*/
SelectObject(hdcBitmap, hOldBitmap);
DeleteDC(hdcBitmap);
if(!himl->hbmMask)
{
DeleteObject(hMaskBitmap);
DeleteDC(hdcMask);
}
return nIndex;
}
/*************************************************************************
* ImageList_BeginDrag [COMCTL32.@]
*
* Creates a temporary image list that contains one image. It will be used
* as a drag image.
*
* PARAMS
* himlTrack [I] handle to the source image list
* iTrack [I] index of the drag image in the source image list
* dxHotspot [I] X position of the hot spot of the drag image
* dyHotspot [I] Y position of the hot spot of the drag image
*
* RETURNS
* Success: TRUE
* Failure: FALSE
*/
BOOL WINAPI
ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
INT dxHotspot, INT dyHotspot)
{
INT cx, cy;
TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
dxHotspot, dyHotspot);
if (!is_valid(himlTrack))
return FALSE;
if (InternalDrag.himl)
ImageList_EndDrag ();
cx = himlTrack->cx;
cy = himlTrack->cy;
InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
if (InternalDrag.himl == NULL) {
WARN("Error creating drag image list!\n");
return FALSE;
}
InternalDrag.dxHotspot = dxHotspot;
InternalDrag.dyHotspot = dyHotspot;
/* copy image */
BitBlt (InternalDrag.himl->hdcImage, 0, 0, cx, cy, himlTrack->hdcImage, iTrack * cx, 0, SRCCOPY);
/* copy mask */
BitBlt (InternalDrag.himl->hdcMask, 0, 0, cx, cy, himlTrack->hdcMask, iTrack * cx, 0, SRCCOPY);
InternalDrag.himl->cCurImage = 1;
return TRUE;
}
/*************************************************************************
* ImageList_Copy [COMCTL32.@]
*
* Copies an image of the source image list to an image of the
* destination image list. Images can be copied or swapped.
*
* PARAMS
* himlDst [I] handle to the destination image list
* iDst [I] destination image index.
* himlSrc [I] handle to the source image list
* iSrc [I] source image index
* uFlags [I] flags for the copy operation
*
* RETURNS
* Success: TRUE
* Failure: FALSE
*
* NOTES
* Copying from one image list to another is possible. The original
* implementation just copies or swaps within one image list.
* Could this feature become a bug??? ;-)
*/
BOOL WINAPI
ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
INT iSrc, UINT uFlags)
{
TRACE("himlDst=%p iDst=%d himlSrc=%p iSrc=%d\n", himlDst, iDst, himlSrc, iSrc);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?