Fixed/implemented the ImageList_*Drag* functions.

This commit is contained in:
Michael Stefaniuc 2001-12-19 18:47:14 +00:00 committed by Alexandre Julliard
parent a77f8d374c
commit 3bc5ffd3c6
1 changed files with 200 additions and 108 deletions

View File

@ -3,11 +3,11 @@
* *
* Copyright 1998 Eric Kohl * Copyright 1998 Eric Kohl
* 2000 Jason Mawdsley. * 2000 Jason Mawdsley.
* 2001 Michael Stefaniuc
* *
* TODO: * TODO:
* - Fix ImageList_DrawIndirect (xBitmap, yBitmap, rgbFg, rgbBk, dwRop). * - Fix ImageList_DrawIndirect (xBitmap, yBitmap, rgbFg, rgbBk, dwRop).
* - Fix ImageList_GetIcon. * - Fix ImageList_GetIcon.
* - Fix drag functions.
* - Fix ImageList_Write. * - Fix ImageList_Write.
* - Fix ImageList_SetFilter (undocumented). * - Fix ImageList_SetFilter (undocumented).
* BTW does anybody know anything about this function??? * BTW does anybody know anything about this function???
@ -23,6 +23,7 @@
* limited in functionality too. * limited in functionality too.
*/ */
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "winerror.h" #include "winerror.h"
#include "winbase.h" #include "winbase.h"
@ -37,21 +38,25 @@ DEFAULT_DEBUG_CHANNEL(imagelist);
#define MAX_OVERLAYIMAGE 15 #define MAX_OVERLAYIMAGE 15
/* internal image list data used for Drag & Drop operations */ /* 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 HIMAGELIST himlInternalDrag = NULL; static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0 };
/* offset of the Hotspot to the origin of the himlInternalDrag image */
static INT nInternalDragHotspotX = 0;
static INT nInternalDragHotspotY = 0;
static HWND hwndInternalDrag = 0;
/* coordinates of the Hotspot relative to the window origin */
static INT nInternalDragPosX = 0;
static INT nInternalDragPosY = 0;
static HDC hdcBackBuffer = 0;
static HBITMAP hbmBackBuffer = 0;
/************************************************************************* /*************************************************************************
@ -76,7 +81,7 @@ IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT c
HBITMAP hbmNewBitmap; HBITMAP hbmNewBitmap;
INT nNewWidth, nNewCount; INT nNewWidth, nNewCount;
if ((himl->cCurImage + nImageCount < himl->cMaxImage) if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
&& (himl->cy >= cy)) && (himl->cy >= cy))
return; return;
@ -459,9 +464,6 @@ IMAGELIST_InternalDrawOverlay(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
} }
/************************************************************************* /*************************************************************************
* ImageList_Add [COMCTL32.40] * ImageList_Add [COMCTL32.40]
* *
@ -707,45 +709,44 @@ ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
HDC hdcSrc, hdcDst; HDC hdcSrc, hdcDst;
INT cx, cy; INT cx, cy;
FIXME("partially implemented!\n");
TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack, TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
dxHotspot, dyHotspot); dxHotspot, dyHotspot);
if (himlTrack == NULL) if (himlTrack == NULL)
return FALSE; return FALSE;
if (InternalDrag.himl)
ImageList_EndDrag ();
cx = himlTrack->cx; cx = himlTrack->cx;
cy = himlTrack->cy; cy = himlTrack->cy;
if (himlInternalDrag) InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
ImageList_EndDrag (); if (InternalDrag.himl == NULL) {
himlInternalDrag = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
if (himlInternalDrag == NULL) {
ERR("Error creating drag image list!\n"); ERR("Error creating drag image list!\n");
return FALSE; return FALSE;
} }
nInternalDragHotspotX = dxHotspot; InternalDrag.dxHotspot = dxHotspot;
nInternalDragHotspotY = dyHotspot; InternalDrag.dyHotspot = dyHotspot;
hdcSrc = CreateCompatibleDC (0); hdcSrc = CreateCompatibleDC (0);
hdcDst = CreateCompatibleDC (0); hdcDst = CreateCompatibleDC (0);
/* copy image */ /* copy image */
SelectObject (hdcSrc, himlTrack->hbmImage); SelectObject (hdcSrc, himlTrack->hbmImage);
SelectObject (hdcDst, himlInternalDrag->hbmImage); SelectObject (hdcDst, InternalDrag.himl->hbmImage);
BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY); BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
/* copy mask */ /* copy mask */
SelectObject (hdcSrc, himlTrack->hbmMask); SelectObject (hdcSrc, himlTrack->hbmMask);
SelectObject (hdcDst, himlInternalDrag->hbmMask); SelectObject (hdcDst, InternalDrag.himl->hbmMask);
BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY); BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
DeleteDC (hdcSrc); DeleteDC (hdcSrc);
DeleteDC (hdcDst); DeleteDC (hdcDst);
himlInternalDrag->cCurImage = 1; InternalDrag.himl->cCurImage = 1;
return TRUE; return TRUE;
} }
@ -1034,24 +1035,23 @@ ImageList_DragEnter (HWND hwndLock, INT x, INT y)
{ {
TRACE("(hwnd=%#x x=%d y=%d)\n", hwndLock, x, y); TRACE("(hwnd=%#x x=%d y=%d)\n", hwndLock, x, y);
if (himlInternalDrag == NULL) if (InternalDrag.himl == NULL)
return FALSE; return FALSE;
if (hwndLock) if (hwndLock)
hwndInternalDrag = hwndLock; InternalDrag.hwnd = hwndLock;
else else
hwndInternalDrag = GetDesktopWindow (); InternalDrag.hwnd = GetDesktopWindow ();
nInternalDragPosX = x; InternalDrag.x = x;
nInternalDragPosY = y; InternalDrag.y = y;
hdcBackBuffer = CreateCompatibleDC (0); /* draw the drag image and save the background */
hbmBackBuffer = CreateCompatibleBitmap (hdcBackBuffer, if (!ImageList_DragShowNolock(TRUE)) {
himlInternalDrag->cx, himlInternalDrag->cy); return FALSE;
}
ImageList_DragShowNolock (TRUE); return TRUE;
return FALSE;
} }
@ -1072,15 +1072,12 @@ BOOL WINAPI
ImageList_DragLeave (HWND hwndLock) ImageList_DragLeave (HWND hwndLock)
{ {
if (hwndLock) if (hwndLock)
hwndInternalDrag = hwndLock; InternalDrag.hwnd = hwndLock;
else else
hwndInternalDrag = GetDesktopWindow (); InternalDrag.hwnd = GetDesktopWindow ();
ImageList_DragShowNolock (FALSE); ImageList_DragShowNolock (FALSE);
DeleteDC (hdcBackBuffer);
DeleteObject (hbmBackBuffer);
return TRUE; return TRUE;
} }
@ -1101,6 +1098,9 @@ ImageList_DragLeave (HWND hwndLock)
* NOTES * NOTES
* The position of the drag image is relative to the window, not * The position of the drag image is relative to the window, not
* the client area. * the client area.
*
* BUGS
* The drag image should be drawn semitransparent.
*/ */
BOOL WINAPI BOOL WINAPI
@ -1108,14 +1108,69 @@ ImageList_DragMove (INT x, INT y)
{ {
TRACE("(x=%d y=%d)\n", x, y); TRACE("(x=%d y=%d)\n", x, y);
ImageList_DragShowNolock (FALSE); if (!InternalDrag.himl) {
return FALSE;
}
nInternalDragPosX = x; /* draw/update the drag image */
nInternalDragPosY = y; if (InternalDrag.bShow) {
HDC hdcDrag;
HDC hdcOffScreen;
HDC hdcBg;
HBITMAP hbmOffScreen;
INT origNewX, origNewY;
INT origOldX, origOldY;
INT origRegX, origRegY;
INT sizeRegX, sizeRegY;
ImageList_DragShowNolock (TRUE); /* calculate the update region */
origNewX = x - InternalDrag.dxHotspot;
origNewY = y - InternalDrag.dyHotspot;
origOldX = InternalDrag.x - InternalDrag.dxHotspot;
origOldY = InternalDrag.y - InternalDrag.dyHotspot;
origRegX = min(origNewX, origOldX);
origRegY = min(origNewY, origOldY);
sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
return FALSE; hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
hdcOffScreen = CreateCompatibleDC(hdcDrag);
hdcBg = CreateCompatibleDC(hdcDrag);
hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
SelectObject(hdcOffScreen, hbmOffScreen);
SelectObject(hdcBg, InternalDrag.hbmBg);
/* get the actual background of the update region */
BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
origRegX, origRegY, SRCCOPY);
/* erase the old image */
BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
SRCCOPY);
/* save the background */
BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
/* draw the image */
/* FIXME: image should be drawn semitransparent */
ImageList_Draw(InternalDrag.himl, 0, hdcOffScreen, origNewX - origRegX,
origNewY - origRegY, ILD_NORMAL);
/* draw the update region to the screen */
BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
hdcOffScreen, 0, 0, SRCCOPY);
DeleteDC(hdcBg);
DeleteDC(hdcOffScreen);
ReleaseDC(InternalDrag.hwnd, hdcDrag);
}
/* update the image position */
InternalDrag.x = x;
InternalDrag.y = y;
return TRUE;
} }
@ -1131,39 +1186,59 @@ ImageList_DragMove (INT x, INT y)
* Success: TRUE * Success: TRUE
* Failure: FALSE * Failure: FALSE
* *
* FIXME * BUGS
* semi-stub. * The drag image should be drawn semitransparent.
*/ */
BOOL WINAPI BOOL WINAPI
ImageList_DragShowNolock (BOOL bShow) ImageList_DragShowNolock (BOOL bShow)
{ {
HDC hdcDrag; HDC hdcDrag;
HDC hdcBg;
INT x, y;
FIXME("semi-stub!\n");
TRACE("bShow=0x%X!\n", bShow); TRACE("bShow=0x%X!\n", bShow);
hdcDrag = GetDCEx (hwndInternalDrag, 0, /* DragImage is already visible/hidden */
if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
return FALSE;
}
/* position of the origin of the DragImage */
x = InternalDrag.x - InternalDrag.dxHotspot;
y = InternalDrag.y - InternalDrag.dyHotspot;
hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE); DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
if (!hdcDrag) {
return FALSE;
}
hdcBg = CreateCompatibleDC(hdcDrag);
if (!InternalDrag.hbmBg) {
InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
InternalDrag.himl->cx, InternalDrag.himl->cy);
}
SelectObject(hdcBg, InternalDrag.hbmBg);
if (bShow) { if (bShow) {
/* show drag image */ /* save the background */
BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
/* save background */ hdcDrag, x, y, SRCCOPY);
/* show the image */
/* draw drag image */ /* FIXME: this should be drawn semitransparent */
ImageList_Draw(InternalDrag.himl, 0, hdcDrag, x, y, ILD_NORMAL);
} } else {
else { /* hide the image */
/* hide drag image */ BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
hdcBg, 0, 0, SRCCOPY);
/* restore background */
} }
ReleaseDC (hwndInternalDrag, hdcDrag); InternalDrag.bShow = !InternalDrag.bShow;
return FALSE; DeleteDC(hdcBg);
ReleaseDC (InternalDrag.hwnd, hdcDrag);
return TRUE;
} }
@ -1397,26 +1472,25 @@ ImageList_Duplicate (HIMAGELIST himlSrc)
* RETURNS * RETURNS
* Success: TRUE * Success: TRUE
* Failure: FALSE * Failure: FALSE
*
* BUGS
* semi-stub.
*/ */
BOOL WINAPI BOOL WINAPI
ImageList_EndDrag (void) ImageList_EndDrag (void)
{ {
FIXME("semi-stub!\n"); /* hide the drag image */
ImageList_DragShowNolock(FALSE);
if (himlInternalDrag) /* cleanup the InternalDrag struct */
{ InternalDrag.hwnd = 0;
ImageList_Destroy (InternalDrag.himl);
ImageList_Destroy (himlInternalDrag); InternalDrag.himl = 0;
himlInternalDrag = NULL; InternalDrag.x= 0;
InternalDrag.y= 0;
nInternalDragHotspotX = 0; InternalDrag.dxHotspot = 0;
nInternalDragHotspotY = 0; InternalDrag.dyHotspot = 0;
InternalDrag.bShow = FALSE;
} DeleteObject(InternalDrag.hbmBg);
InternalDrag.hbmBg = 0;
return TRUE; return TRUE;
} }
@ -1457,24 +1531,21 @@ ImageList_GetBkColor (HIMAGELIST himl)
* RETURNS * RETURNS
* Success: Handle of the drag image list. * Success: Handle of the drag image list.
* Failure: NULL. * Failure: NULL.
*
* BUGS
* semi-stub.
*/ */
HIMAGELIST WINAPI HIMAGELIST WINAPI
ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot) ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
{ {
if (himlInternalDrag) { if (InternalDrag.himl) {
if (ppt) { if (ppt) {
ppt->x = nInternalDragPosX; ppt->x = InternalDrag.x;
ppt->y = nInternalDragPosY; ppt->y = InternalDrag.y;
} }
if (pptHotspot) { if (pptHotspot) {
pptHotspot->x = nInternalDragHotspotX; pptHotspot->x = InternalDrag.dxHotspot;
pptHotspot->y = nInternalDragHotspotY; pptHotspot->y = InternalDrag.dyHotspot;
} }
return (himlInternalDrag); return (InternalDrag.himl);
} }
return NULL; return NULL;
@ -2395,7 +2466,7 @@ ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp); GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
if (i == -1) { if (i == -1) {
if (himl->cCurImage + 1 >= himl->cMaxImage) if (himl->cCurImage + 1 > himl->cMaxImage)
IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0); IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
nIndex = himl->cCurImage; nIndex = himl->cCurImage;
@ -2489,8 +2560,10 @@ ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
* Success: TRUE * Success: TRUE
* Failure: FALSE * Failure: FALSE
* *
* BUGS * NOTES
* semi-stub. * When this function is called and the drag image is visible, a
* short flickering occurs but this matches the Win9x behavior. It is
* possible to fix the flickering using code like in ImageList_DragMove.
*/ */
BOOL WINAPI BOOL WINAPI
@ -2499,32 +2572,51 @@ ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
{ {
HIMAGELIST himlTemp; HIMAGELIST himlTemp;
INT dx, dy; INT dx, dy;
BOOL visible;
if (himlInternalDrag == NULL) if (InternalDrag.himl == NULL)
return FALSE; return FALSE;
TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n", TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
dxHotspot, dyHotspot, nInternalDragHotspotX, nInternalDragHotspotY); dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
visible = InternalDrag.bShow;
/* Calculate the offset between the origin of the old image and the /* Calculate the offset between the origin of the old image and the
* origin of the second image. * origin of the second image.
* dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
* hotspot) to the origin of the second image (himlDrag). * hotspot) to the origin of the second image.
* See M$DN for details */ * See M$DN for details */
dx = nInternalDragHotspotX - dxHotspot; dx = InternalDrag.dxHotspot - dxHotspot;
dy = nInternalDragHotspotY - dyHotspot; dy = InternalDrag.dyHotspot - dyHotspot;
himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
himlTemp = ImageList_Merge (himlInternalDrag, 0, himlDrag, iDrag, dx, dy); if (visible) {
ImageList_Destroy (himlInternalDrag); /* hide the drag image */
himlInternalDrag = himlTemp; ImageList_DragShowNolock(FALSE);
/* update the InternalDragOffset, if the origin of the origin of the
* DragImage was changed by ImageList_Merge. */
if (dx > nInternalDragHotspotX) {
nInternalDragHotspotX = dx;
} }
if (dy > nInternalDragHotspotY) { if ((InternalDrag.himl->cx != himlTemp->cx) ||
nInternalDragHotspotY = dy; (InternalDrag.himl->cy != himlTemp->cy)) {
/* the size of the drag image changed, invalidate the buffer */
DeleteObject(InternalDrag.hbmBg);
InternalDrag.hbmBg = 0;
}
ImageList_Destroy (InternalDrag.himl);
InternalDrag.himl = himlTemp;
/* update the InternalDragOffset, if the origin of the
* DragImage was changed by ImageList_Merge. */
if (dx > InternalDrag.dxHotspot) {
InternalDrag.dxHotspot = dx;
}
if (dy > InternalDrag.dyHotspot) {
InternalDrag.dyHotspot = dy;
}
if (visible) {
/* show the drag image */
ImageList_DragShowNolock(TRUE);
} }
return TRUE; return TRUE;