mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 01:24:38 +00:00
Patch by Jonathon Wilson: Implemented loading cursors with LoadImage()
svn path=/trunk/; revision=5702
This commit is contained in:
parent
545e6f33fb
commit
f8dadc910b
5 changed files with 251 additions and 54 deletions
|
@ -15,27 +15,50 @@ typedef struct _ICONIMAGE
|
|||
BYTE icAND[1]; // DIB bits for AND mask
|
||||
} ICONIMAGE, *LPICONIMAGE __attribute__((packed));
|
||||
|
||||
typedef struct _CURSORIMAGE
|
||||
{
|
||||
BITMAPINFOHEADER icHeader; // DIB header
|
||||
RGBQUAD icColors[1]; // Color table
|
||||
BYTE icXOR[1]; // DIB bits for XOR mask
|
||||
BYTE icAND[1]; // DIB bits for AND mask
|
||||
} CURSORIMAGE, *LPCURSORIMAGE __attribute__((packed));
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BYTE bWidth;
|
||||
BYTE bHeight;
|
||||
BYTE bColorCount;
|
||||
BYTE bReserved;
|
||||
} ICONRESDIR __attribute__((packed));
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD wWidth;
|
||||
WORD wHeight;
|
||||
} CURSORRESDIR __attribute__((packed));
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD wPlanes; // Number of Color Planes in the XOR image
|
||||
WORD wBitCount; // Bits per pixel in the XOR image
|
||||
} ICONDIR __attribute__((packed));
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD wXHotspot; // Number of Color Planes in the XOR image
|
||||
WORD wYHotspot; // Bits per pixel in the XOR image
|
||||
} CURSORDIR __attribute__((packed));
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BYTE bWidth; // Width, in pixels, of the icon image
|
||||
BYTE bHeight; // Height, in pixels, of the icon image
|
||||
BYTE bColorCount; // Number of colors in image (0 if >=8bpp)
|
||||
BYTE bReserved; // Reserved ( must be 0)
|
||||
} ICONDIR __attribute__((packed));
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD wWidth; //Width, in pixels of the cursor image
|
||||
WORD wHeight; //Hight, in pixles of the cursor image
|
||||
} CURSORDIR __attribute__((packed));
|
||||
|
||||
typedef struct
|
||||
{ union
|
||||
union
|
||||
{ ICONDIR icon;
|
||||
CURSORDIR cursor;
|
||||
} Info;
|
||||
WORD wPlanes; // Number of Color Planes in the XOR image
|
||||
WORD wBitCount; // Bits per pixel in the XOR image
|
||||
DWORD dwBytesInRes; // How many bytes in this resource?
|
||||
DWORD dwImageOffset; // Where in the file is this image?
|
||||
} CURSORICONDIRENTRY __attribute__((packed));
|
||||
|
@ -49,23 +72,24 @@ typedef struct
|
|||
} CURSORICONDIR __attribute__((packed));
|
||||
|
||||
typedef struct
|
||||
{ union
|
||||
{ ICONDIR icon;
|
||||
CURSORDIR cursor;
|
||||
} Info;
|
||||
WORD wPlanes; // Color Planes
|
||||
WORD wBitCount; // Bits per pixel
|
||||
DWORD dwBytesInRes; // how many bytes in this resource?
|
||||
WORD nID; // the ID
|
||||
} GRPICONDIRENTRY __attribute__((packed));
|
||||
{
|
||||
union
|
||||
{ ICONRESDIR icon;
|
||||
CURSORRESDIR cursor;
|
||||
} ResInfo;
|
||||
WORD wPlanes; // Color Planes
|
||||
WORD wBitCount; // Bits per pixel
|
||||
DWORD dwBytesInRes; // how many bytes in this resource?
|
||||
WORD nID; // the ID
|
||||
} GRPCURSORICONDIRENTRY __attribute__((packed));
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD idReserved; // Reserved (must be 0)
|
||||
WORD idType; // Resource type (1 for icons)
|
||||
WORD idCount; // How many images?
|
||||
GRPICONDIRENTRY idEntries[1] __attribute__((packed)); // The entries for each image
|
||||
} GRPICONDIR __attribute__((packed));
|
||||
GRPCURSORICONDIRENTRY idEntries[1] __attribute__((packed)); // The entries for each image
|
||||
} GRPCURSORICONDIR __attribute__((packed));
|
||||
|
||||
/* GDI logical Icon/Cursor object */
|
||||
typedef struct _ICONCURSOROBJ
|
||||
|
|
|
@ -441,8 +441,7 @@ LockWindowUpdate@4
|
|||
LockWorkStation@0
|
||||
LookupIconIdFromDirectory@8
|
||||
LookupIconIdFromDirectoryEx@20
|
||||
;MBToWCSEx
|
||||
;MB_GetString
|
||||
MBToWCSEx@24
|
||||
MapDialogRect@8
|
||||
MapVirtualKeyA@8
|
||||
MapVirtualKeyExA@12
|
||||
|
@ -680,7 +679,7 @@ VkKeyScanA@4
|
|||
VkKeyScanExA@8
|
||||
VkKeyScanExW@8
|
||||
VkKeyScanW@4
|
||||
;WCSToMBEx
|
||||
WCSToMBEx@24
|
||||
;WINNLSEnableIME
|
||||
;WINNLSGetEnableStatus
|
||||
;WINNLSGetIMEHotkey
|
||||
|
|
|
@ -442,8 +442,7 @@ LockWindowUpdate=LockWindowUpdate@4
|
|||
LockWorkStation=LockWorkStation@0
|
||||
LookupIconIdFromDirectory=LookupIconIdFromDirectory@8
|
||||
LookupIconIdFromDirectoryEx=LookupIconIdFromDirectoryEx@20
|
||||
;MBToWCSEx
|
||||
;MB_GetString
|
||||
MBToWCSEx=MBToWCSEx@24
|
||||
MapDialogRect=MapDialogRect@8
|
||||
MapVirtualKeyA=MapVirtualKeyA@8
|
||||
MapVirtualKeyExA=MapVirtualKeyExA@12
|
||||
|
@ -684,7 +683,7 @@ VkKeyScanA=VkKeyScanA@4
|
|||
VkKeyScanExA=VkKeyScanExA@8
|
||||
VkKeyScanExW=VkKeyScanExW@8
|
||||
VkKeyScanW=VkKeyScanW@4
|
||||
;WCSToMBEx
|
||||
WCSToMBEx=WCSToMBEx@24
|
||||
;WINNLSEnableIME
|
||||
;WINNLSGetEnableStatus
|
||||
;WINNLSGetIMEHotkey
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/* $Id: bitmap.c,v 1.12 2003/08/07 04:03:24 royce Exp $
|
||||
/* $Id: bitmap.c,v 1.13 2003/08/20 14:08:18 weiden Exp $
|
||||
*
|
||||
* PROJECT: ReactOS user32.dll
|
||||
* FILE: lib/user32/windows/input.c
|
||||
|
@ -35,8 +35,9 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
/*forward declerations... actualy in user32\windows\icon.c but usful here****/
|
||||
HICON ICON_CreateIconFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired);
|
||||
HICON ICON_CreateIconFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot);
|
||||
CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width, int height, int colors);
|
||||
CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir, int width, int height, int colors);
|
||||
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
@ -76,8 +77,166 @@ LoadImageA(HINSTANCE hinst,
|
|||
HANDLE STATIC
|
||||
LoadCursorImage(HINSTANCE hinst, LPCWSTR lpszName, UINT fuLoad)
|
||||
{
|
||||
DbgPrint("FIXME: Need support for loading cursor images.\n");
|
||||
return(NULL);
|
||||
HANDLE hResource;
|
||||
HANDLE h2Resource;
|
||||
HANDLE hFile;
|
||||
HANDLE hSection;
|
||||
CURSORICONDIR* IconDIR;
|
||||
HDC hScreenDc;
|
||||
HANDLE hIcon;
|
||||
ULONG HeaderSize;
|
||||
ULONG ColourCount;
|
||||
PVOID Data;
|
||||
CURSORICONDIRENTRY* dirEntry;
|
||||
ICONIMAGE* SafeIconImage;
|
||||
GRPCURSORICONDIR* IconResDir;
|
||||
INT id;
|
||||
ICONIMAGE *ResIcon;
|
||||
|
||||
if (fuLoad & LR_SHARED)
|
||||
DbgPrint("FIXME: need LR_SHARED support Loading cursor images\n");
|
||||
|
||||
if (!(fuLoad & LR_LOADFROMFILE))
|
||||
{
|
||||
if (hinst == NULL)
|
||||
{
|
||||
hinst = GetModuleHandleW(L"USER32");
|
||||
}
|
||||
hResource = FindResourceW(hinst, lpszName, RT_GROUP_CURSOR);
|
||||
if (hResource == NULL)
|
||||
{
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
hResource = LoadResource(hinst, hResource);
|
||||
if (hResource == NULL)
|
||||
{
|
||||
return(NULL);
|
||||
}
|
||||
IconResDir = LockResource(hResource);
|
||||
if (IconResDir == NULL)
|
||||
{
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
//find the best fitting in the IconResDir for this resolution
|
||||
id = LookupIconIdFromDirectoryEx((PBYTE) IconResDir, TRUE,
|
||||
32, 32, fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
|
||||
|
||||
h2Resource = FindResourceW(hinst,
|
||||
MAKEINTRESOURCEW(id),
|
||||
MAKEINTRESOURCEW(RT_ICON));
|
||||
|
||||
hResource = LoadResource(hinst, h2Resource);
|
||||
if (hResource == NULL)
|
||||
{
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
ResIcon = LockResource(hResource);
|
||||
if (ResIcon == NULL)
|
||||
{
|
||||
return(NULL);
|
||||
}
|
||||
return CreateIconFromResourceEx((PBYTE) ResIcon,
|
||||
SizeofResource(hinst, h2Resource), FALSE, 0x00030000,
|
||||
32, 32, fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
|
||||
}
|
||||
else
|
||||
{
|
||||
hFile = CreateFileW(lpszName,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL);
|
||||
if (hFile == NULL)
|
||||
{
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
hSection = CreateFileMappingW(hFile,
|
||||
NULL,
|
||||
PAGE_READONLY,
|
||||
0,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
CloseHandle(hFile);
|
||||
if (hSection == NULL)
|
||||
{
|
||||
return(NULL);
|
||||
}
|
||||
IconDIR = MapViewOfFile(hSection,
|
||||
FILE_MAP_READ,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
|
||||
CloseHandle(hSection);
|
||||
if (IconDIR == NULL)
|
||||
{
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
//pick the best size.
|
||||
dirEntry = (CURSORICONDIRENTRY *) CURSORICON_FindBestIcon( IconDIR, 32, 32, 1);
|
||||
|
||||
|
||||
if (!dirEntry)
|
||||
{
|
||||
if (fuLoad & LR_LOADFROMFILE)
|
||||
{
|
||||
UnmapViewOfFile(IconDIR);
|
||||
}
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
SafeIconImage = RtlAllocateHeap(RtlGetProcessHeap(), 0, dirEntry->dwBytesInRes);
|
||||
|
||||
memcpy(SafeIconImage, ((PBYTE)IconDIR) + dirEntry->dwImageOffset, dirEntry->dwBytesInRes);
|
||||
}
|
||||
|
||||
//at this point we have a copy of the icon image to play with
|
||||
|
||||
SafeIconImage->icHeader.biHeight = SafeIconImage->icHeader.biHeight /2;
|
||||
|
||||
if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
|
||||
{
|
||||
BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)SafeIconImage;
|
||||
ColourCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
|
||||
HeaderSize = sizeof(BITMAPCOREHEADER) + ColourCount * sizeof(RGBTRIPLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
ColourCount = SafeIconImage->icHeader.biClrUsed;
|
||||
if (ColourCount == 0 && SafeIconImage->icHeader.biBitCount <= 8)
|
||||
{
|
||||
ColourCount = 1 << SafeIconImage->icHeader.biBitCount;
|
||||
}
|
||||
HeaderSize = sizeof(BITMAPINFOHEADER) + ColourCount * sizeof(RGBQUAD);
|
||||
}
|
||||
|
||||
//make data point to the start of the XOR image data
|
||||
Data = (PBYTE)SafeIconImage + HeaderSize;
|
||||
|
||||
|
||||
//get a handle to the screen dc, the icon we create is going to be compatable with this
|
||||
hScreenDc = CreateDCW(L"DISPLAY", NULL, NULL, NULL);
|
||||
if (hScreenDc == NULL)
|
||||
{
|
||||
if (fuLoad & LR_LOADFROMFILE)
|
||||
{
|
||||
RtlFreeHeap(RtlGetProcessHeap(), 0, SafeIconImage);
|
||||
UnmapViewOfFile(IconDIR);
|
||||
}
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
hIcon = ICON_CreateIconFromData(hScreenDc, Data, SafeIconImage, 32, 32, dirEntry->Info.cursor.wXHotspot, dirEntry->Info.cursor.wYHotspot);
|
||||
RtlFreeHeap(RtlGetProcessHeap(), 0, SafeIconImage);
|
||||
return hIcon;
|
||||
}
|
||||
|
||||
|
||||
|
@ -96,7 +255,7 @@ LoadIconImage(HINSTANCE hinst, LPCWSTR lpszName, INT width, INT height, UINT fuL
|
|||
PVOID Data;
|
||||
CURSORICONDIRENTRY* dirEntry;
|
||||
ICONIMAGE* SafeIconImage;
|
||||
GRPICONDIR* IconResDir;
|
||||
GRPCURSORICONDIR* IconResDir;
|
||||
INT id;
|
||||
ICONIMAGE *ResIcon;
|
||||
|
||||
|
@ -241,7 +400,7 @@ LoadIconImage(HINSTANCE hinst, LPCWSTR lpszName, INT width, INT height, UINT fuL
|
|||
return(NULL);
|
||||
}
|
||||
|
||||
hIcon = ICON_CreateIconFromData(hScreenDc, Data, SafeIconImage, width, height);
|
||||
hIcon = ICON_CreateIconFromData(hScreenDc, Data, SafeIconImage, width, height, width/2, height/2);
|
||||
RtlFreeHeap(RtlGetProcessHeap(), 0, SafeIconImage);
|
||||
return hIcon;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/* $Id: icon.c,v 1.8 2003/08/19 11:48:49 weiden Exp $
|
||||
/* $Id: icon.c,v 1.9 2003/08/20 14:08:19 weiden Exp $
|
||||
*
|
||||
* PROJECT: ReactOS user32.dll
|
||||
* FILE: lib/user32/windows/icon.c
|
||||
|
@ -37,7 +37,7 @@
|
|||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
HICON
|
||||
ICON_CreateIconFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired)
|
||||
ICON_CreateIconFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot)
|
||||
{
|
||||
HANDLE hXORBitmap;
|
||||
HANDLE hANDBitmap;
|
||||
|
@ -87,8 +87,8 @@ ICON_CreateIconFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDe
|
|||
RtlFreeHeap(RtlGetProcessHeap(), 0, bwBIH);
|
||||
|
||||
IconInfo.fIcon = TRUE;
|
||||
IconInfo.xHotspot = cxDesired/2;
|
||||
IconInfo.yHotspot = cyDesired/2;
|
||||
IconInfo.xHotspot = xHotspot;
|
||||
IconInfo.yHotspot = yHotspot;
|
||||
IconInfo.hbmColor = hXORBitmap;
|
||||
IconInfo.hbmMask = hANDBitmap;
|
||||
|
||||
|
@ -179,8 +179,24 @@ CreateIconFromResourceEx(
|
|||
ULONG ColourCount;
|
||||
PVOID Data;
|
||||
HDC hScreenDc;
|
||||
WORD wXHotspot;
|
||||
WORD wYHotspot;
|
||||
|
||||
DPRINT("fIcon, dwVersion, cxDesired, cyDesired are all ignored in this implementation!\n");
|
||||
DPRINT("dwVersion, cxDesired, cyDesired are all ignored in this implementation!\n");
|
||||
|
||||
if (!fIcon)
|
||||
{
|
||||
wXHotspot = (WORD)*pbIconBits;
|
||||
pbIconBits+=2;
|
||||
wYHotspot = (WORD)*pbIconBits;
|
||||
pbIconBits+=2;
|
||||
cbIconBits-=4;
|
||||
}
|
||||
else
|
||||
{
|
||||
wXHotspot = cxDesired / 2;
|
||||
wYHotspot = cyDesired / 2;
|
||||
}
|
||||
|
||||
//get an safe copy of the icon data
|
||||
SafeIconImage = RtlAllocateHeap(RtlGetProcessHeap(), 0, cbIconBits);
|
||||
|
@ -213,7 +229,7 @@ CreateIconFromResourceEx(
|
|||
return(NULL);
|
||||
}
|
||||
|
||||
hIcon = ICON_CreateIconFromData(hScreenDc, Data, SafeIconImage, cxDesired, cyDesired);
|
||||
hIcon = ICON_CreateIconFromData(hScreenDc, Data, SafeIconImage, cxDesired, cyDesired, wXHotspot, wYHotspot);
|
||||
RtlFreeHeap(RtlGetProcessHeap(), 0, SafeIconImage);
|
||||
return hIcon;
|
||||
}
|
||||
|
@ -497,8 +513,8 @@ CURSORICON_FindBestCursor( CURSORICONDIR *dir, int width, int height, int colors
|
|||
iColorDiff = 0xFFFFFFFF;
|
||||
for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
|
||||
{
|
||||
iTempXDiff = abs(width - entry->Info.icon.bWidth);
|
||||
iTempYDiff = abs(height - entry->Info.icon.bHeight);
|
||||
iTempXDiff = abs(width - entry->bWidth);
|
||||
iTempYDiff = abs(height - entry->bHeight);
|
||||
|
||||
if(iTotalDiff > (iTempXDiff + iTempYDiff))
|
||||
{
|
||||
|
@ -511,10 +527,10 @@ CURSORICON_FindBestCursor( CURSORICONDIR *dir, int width, int height, int colors
|
|||
/* Find Best Colors for Best Fit */
|
||||
for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
|
||||
{
|
||||
if(abs(width - entry->Info.icon.bWidth) == (int) iXDiff &&
|
||||
abs(height - entry->Info.icon.bHeight) == (int) iYDiff)
|
||||
if(abs(width - entry->bWidth) == (int) iXDiff &&
|
||||
abs(height - entry->bHeight) == (int) iYDiff)
|
||||
{
|
||||
iTempColorDiff = abs(colors - entry->Info.icon.bColorCount);
|
||||
iTempColorDiff = abs(colors - entry->bColorCount);
|
||||
|
||||
if(iColorDiff > iTempColorDiff)
|
||||
{
|
||||
|
@ -549,9 +565,9 @@ CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width, int height, int colors)
|
|||
iColorDiff = 0xFFFFFFFF;
|
||||
for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
|
||||
{
|
||||
iTempXDiff = abs(width - entry->Info.icon.bWidth);
|
||||
iTempXDiff = abs(width - entry->bWidth);
|
||||
|
||||
iTempYDiff = abs(height - entry->Info.icon.bHeight);
|
||||
iTempYDiff = abs(height - entry->bHeight);
|
||||
|
||||
if(iTotalDiff > (iTempXDiff + iTempYDiff))
|
||||
{
|
||||
|
@ -564,10 +580,10 @@ CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width, int height, int colors)
|
|||
/* Find Best Colors for Best Fit */
|
||||
for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
|
||||
{
|
||||
if(abs(width - entry->Info.icon.bWidth) == (int) iXDiff &&
|
||||
abs(height - entry->Info.icon.bHeight) == (int) iYDiff)
|
||||
if(abs(width - entry->bWidth) == (int) iXDiff &&
|
||||
abs(height - entry->bHeight) == (int) iYDiff)
|
||||
{
|
||||
iTempColorDiff = abs(colors - entry->Info.icon.bColorCount);
|
||||
iTempColorDiff = abs(colors - entry->bColorCount);
|
||||
if(iColorDiff > iTempColorDiff)
|
||||
{
|
||||
bestEntry = entry;
|
||||
|
@ -592,12 +608,12 @@ LookupIconIdFromDirectoryEx(
|
|||
int cyDesired,
|
||||
UINT Flags)
|
||||
{
|
||||
GRPICONDIR *dir = (GRPICONDIR*)presbits;
|
||||
GRPCURSORICONDIR *dir = (GRPCURSORICONDIR*)presbits;
|
||||
UINT retVal = 0;
|
||||
|
||||
if( dir && !dir->idReserved && (dir->idType & 3) )
|
||||
{
|
||||
GRPICONDIRENTRY* entry;
|
||||
GRPCURSORICONDIRENTRY* entry;
|
||||
HDC hdc;
|
||||
UINT palEnts;
|
||||
int colors;
|
||||
|
@ -612,7 +628,7 @@ LookupIconIdFromDirectoryEx(
|
|||
|
||||
ReleaseDC(0, hdc);
|
||||
|
||||
entry = (GRPICONDIRENTRY*)CURSORICON_FindBestIcon( (CURSORICONDIR*)dir,
|
||||
entry = (GRPCURSORICONDIRENTRY*)CURSORICON_FindBestIcon( (CURSORICONDIR*)dir,
|
||||
cxDesired,
|
||||
cyDesired,
|
||||
colors );
|
||||
|
|
Loading…
Reference in a new issue