mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 14:16:07 -06:00
651 lines
17 KiB
C++
651 lines
17 KiB
C++
#include "CtrlCore.h"
|
|
|
|
#ifdef GUI_WIN
|
|
|
|
#include <shellapi.h>
|
|
|
|
namespace Upp {
|
|
|
|
#define LTIMING(x) // RTIMING(x)
|
|
#define LLOG(x) // DLOG(x)
|
|
|
|
bool ImageFallBack
|
|
// = true
|
|
;
|
|
|
|
class BitmapInfo32__ {
|
|
union {
|
|
BITMAPV5HEADER bi;
|
|
BITMAPINFOHEADER hi;
|
|
};
|
|
|
|
public:
|
|
operator BITMAPINFO *() { return (BITMAPINFO *)&bi; }
|
|
operator BITMAPINFOHEADER *() { return (BITMAPINFOHEADER *)&bi; }
|
|
BITMAPINFOHEADER *operator->() { return (BITMAPINFOHEADER *)&bi; }
|
|
|
|
BitmapInfo32__(int cx, int cy, bool surface = false);
|
|
};
|
|
|
|
BitmapInfo32__::BitmapInfo32__(int cx, int cy, bool surface)
|
|
{
|
|
if(surface) {
|
|
ZeroMemory(&hi, sizeof(BITMAPINFOHEADER));
|
|
hi.biSize = sizeof(BITMAPINFOHEADER);
|
|
hi.biPlanes = 1;
|
|
hi.biBitCount = 32;
|
|
hi.biCompression = BI_RGB;
|
|
hi.biSizeImage = 0;
|
|
hi.biClrUsed = 0;
|
|
hi.biClrImportant = 0;
|
|
hi.biWidth = cx;
|
|
hi.biHeight = -cy;
|
|
}
|
|
else {
|
|
ZeroMemory(&bi, sizeof(BITMAPV5HEADER));
|
|
bi.bV5Size = sizeof(BITMAPV5HEADER);
|
|
bi.bV5Width = cx;
|
|
bi.bV5Height = -cy;
|
|
bi.bV5Planes = 1;
|
|
bi.bV5BitCount = 32;
|
|
bi.bV5Compression = BI_BITFIELDS;
|
|
bi.bV5RedMask = 0x00FF0000;
|
|
bi.bV5GreenMask = 0x0000FF00;
|
|
bi.bV5BlueMask = 0x000000FF;
|
|
bi.bV5AlphaMask = 0xFF000000;
|
|
bi.bV5CSType = LCS_sRGB;
|
|
}
|
|
}
|
|
|
|
HBITMAP CreateBitMask(const RGBA *data, Size sz, Size tsz, Size csz, RGBA *ct)
|
|
{
|
|
LTIMING("CreateBitMask");
|
|
GuiLock __;
|
|
Fill(ct, RGBAZero(), tsz.cx * tsz.cy);
|
|
int linelen = (tsz.cx + 15) >> 4 << 1;
|
|
Buffer<byte> mask(tsz.cy * linelen, 0xff);
|
|
byte *m = mask;
|
|
RGBA *ty = ct;
|
|
const RGBA *sy = data;
|
|
for(int y = 0; y < csz.cy; y++) {
|
|
const RGBA *s = sy;
|
|
RGBA *t = ty;
|
|
for(int x = 0; x < csz.cx; x++) {
|
|
if(s->a > 128) {
|
|
*t = *s;
|
|
m[x >> 3] &= ~(0x80 >> (x & 7));
|
|
}
|
|
else
|
|
t->r = t->g = t->b = 0;
|
|
t->a = 0;
|
|
t++;
|
|
s++;
|
|
}
|
|
m += linelen;
|
|
sy += sz.cx;
|
|
ty += tsz.cx;
|
|
}
|
|
return ::CreateBitmap(tsz.cx, tsz.cy, 1, 1, mask);
|
|
}
|
|
|
|
void SetSurface(HDC dc, const Rect& dest, const RGBA *pixels, Size srcsz, Point srcoff)
|
|
{
|
|
LTIMING("SetSurface");
|
|
GuiLock __;
|
|
BitmapInfo32__ bi(srcsz.cx, srcsz.cy, true);
|
|
::SetDIBitsToDevice(dc, dest.left, dest.top, dest.GetWidth(), dest.GetHeight(),
|
|
srcoff.x, -srcoff.y - dest.Height() + srcsz.cy, 0, srcsz.cy, pixels, bi,
|
|
DIB_RGB_COLORS);
|
|
}
|
|
|
|
void SetSurface(HDC dc, int x, int y, int cx, int cy, const RGBA *pixels)
|
|
{
|
|
SetSurface(dc, RectC(x, y, cx, cy), pixels, Size(cx, cy), Point(0, 0));
|
|
}
|
|
|
|
void SetSurface(SystemDraw& w, int x, int y, int cx, int cy, const RGBA *pixels)
|
|
{
|
|
SetSurface(w.GetHandle(), x, y, cx, cy, pixels);
|
|
}
|
|
|
|
void SetSurface(SystemDraw& w, const Rect& dest, const RGBA *pixels, Size psz, Point poff)
|
|
{
|
|
SetSurface(w.GetHandle(), dest, pixels, psz, poff);
|
|
}
|
|
|
|
class DrawSurface : NoCopy {
|
|
int x, y;
|
|
Size size;
|
|
RGBA *pixels;
|
|
HDC dc, dcMem;
|
|
HBITMAP hbmp, hbmpOld;
|
|
|
|
void Init(SystemDraw& w, int x, int y, int cx, int cy);
|
|
RGBA* Line(int i) const { ASSERT(i >= 0 && i < size.cy); return (RGBA *)pixels + size.cx * (size.cy - i - 1); }
|
|
|
|
public:
|
|
operator RGBA *() { return pixels; }
|
|
Size GetSize() const { return size; }
|
|
RGBA *operator[](int i) { return Line(i); }
|
|
const RGBA *operator[](int i) const { return Line(i); }
|
|
int GetLineDelta() const { return -size.cx; }
|
|
|
|
DrawSurface(SystemDraw& w, const Rect& r);
|
|
DrawSurface(SystemDraw& w, int x, int y, int cx, int cy);
|
|
~DrawSurface();
|
|
};
|
|
|
|
void DrawSurface::Init(SystemDraw& w, int _x, int _y, int cx, int cy)
|
|
{
|
|
LTIMING("DrawSurface");
|
|
GuiLock __;
|
|
dc = w.GetHandle();
|
|
size = Size(cx, cy);
|
|
x = _x;
|
|
y = _y;
|
|
dcMem = ::CreateCompatibleDC(dc);
|
|
BitmapInfo32__ bi(cx, cy, true);
|
|
hbmp = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (void **)&pixels, NULL, 0);
|
|
hbmpOld = (HBITMAP) ::SelectObject(dcMem, hbmp);
|
|
::BitBlt(dcMem, 0, 0, cx, cy, dc, x, y, SRCCOPY);
|
|
}
|
|
|
|
DrawSurface::DrawSurface(SystemDraw& w, const Rect& r)
|
|
{
|
|
Init(w, r.left, r.top, r.Width(), r.Height());
|
|
}
|
|
|
|
DrawSurface::DrawSurface(SystemDraw& w, int x, int y, int cx, int cy)
|
|
{
|
|
Init(w, x, y, cx, cy);
|
|
}
|
|
|
|
DrawSurface::~DrawSurface()
|
|
{
|
|
GuiLock __;
|
|
::BitBlt(dc, x, y, size.cx, size.cy, dcMem, 0, 0, SRCCOPY);
|
|
::DeleteObject(::SelectObject(dcMem, hbmpOld));
|
|
::DeleteDC(dcMem);
|
|
}
|
|
|
|
#ifndef PLATFORM_WINCE
|
|
typedef BOOL (WINAPI *tAlphaBlend)(HDC hdcDest, int nXOriginDest, int nYOriginDest,
|
|
int nWidthDest, int nHeightDest,
|
|
HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
|
|
int nWidthSrc, int nHeightSrc, BLENDFUNCTION blendFunction);
|
|
|
|
static tAlphaBlend fnAlphaBlend()
|
|
{
|
|
GuiLock __;
|
|
static tAlphaBlend pSet;
|
|
static bool inited = false;
|
|
if(!inited) {
|
|
inited = true;
|
|
if(HMODULE hDLL = LoadLibrary("msimg32.dll"))
|
|
pSet = (tAlphaBlend) GetProcAddress(hDLL, "AlphaBlend");
|
|
}
|
|
return pSet;
|
|
}
|
|
#endif
|
|
|
|
struct ImageSysData {
|
|
Image img;
|
|
HBITMAP hbmp;
|
|
HBITMAP hmask;
|
|
HBITMAP himg;
|
|
RGBA *section;
|
|
|
|
void Init(const Image& img);
|
|
void CreateHBMP(HDC dc, const RGBA *data);
|
|
void Paint(SystemDraw& w, int x, int y, const Rect& src, Color c);
|
|
|
|
~ImageSysData();
|
|
};
|
|
|
|
void ImageSysData::Init(const Image& _img)
|
|
{
|
|
img = _img;
|
|
hbmp = hmask = himg = NULL;
|
|
LLOG("ImageSysData::Init " << img.GetSerialId() << " " << img.GetSize());
|
|
}
|
|
|
|
ImageSysData::~ImageSysData()
|
|
{
|
|
SysImageReleased(img);
|
|
if(hbmp) {
|
|
GuiLock __;
|
|
DeleteObject(hbmp);
|
|
}
|
|
if(hmask) {
|
|
GuiLock __;
|
|
DeleteObject(hmask);
|
|
}
|
|
if(himg) {
|
|
GuiLock __;
|
|
DeleteObject(himg);
|
|
}
|
|
hbmp = hmask = himg = NULL;
|
|
img.Clear();
|
|
}
|
|
|
|
void ImageSysData::CreateHBMP(HDC dc, const RGBA *data)
|
|
{
|
|
LTIMING("CreateHBMP");
|
|
LLOG("Creating BMP for " << img.GetSerialId() << ' ' << img.GetSize());
|
|
Size sz = img.GetSize();
|
|
BitmapInfo32__ bi(sz.cx, sz.cy);
|
|
HDC dcMem = ::CreateCompatibleDC(dc);
|
|
RGBA *pixels;
|
|
HBITMAP hbmp32 = CreateDIBSection(dcMem, bi, DIB_RGB_COLORS, (void **)&pixels, NULL, 0);
|
|
HDC hbmpOld = (HDC) ::SelectObject(dcMem, hbmp32);
|
|
Copy(pixels, data, (int)img.GetLength());
|
|
HDC dcMem2 = ::CreateCompatibleDC(dc);
|
|
hbmp = ::CreateCompatibleBitmap(dc, sz.cx, sz.cy);
|
|
HBITMAP o2 = (HBITMAP)::SelectObject(dcMem2, hbmp);
|
|
::BitBlt(dcMem2, 0, 0, sz.cx, sz.cy, dcMem, 0, 0, SRCCOPY);
|
|
::SelectObject(dcMem2, o2);
|
|
::DeleteDC(dcMem2);
|
|
::SelectObject(dcMem, hbmpOld);
|
|
::DeleteObject(hbmp32);
|
|
::DeleteDC(dcMem);
|
|
}
|
|
|
|
void ImageSysData::Paint(SystemDraw& w, int x, int y, const Rect& src, Color c)
|
|
{
|
|
HDC dc = w.GetHandle();
|
|
Size sz = img.GetSize();
|
|
int len = sz.cx * sz.cy;
|
|
Rect sr = src & sz;
|
|
Size ssz = sr.Size();
|
|
if(sr.IsEmpty())
|
|
return;
|
|
|
|
if(fnAlphaBlend() && IsNull(c) && !ImageFallBack &&
|
|
!(w.IsPrinter() && (GetDeviceCaps(dc, SHADEBLENDCAPS) & (SB_PIXEL_ALPHA|SB_PREMULT_ALPHA)) !=
|
|
(SB_PIXEL_ALPHA|SB_PREMULT_ALPHA))) {
|
|
if(!himg) {
|
|
LTIMING("Image Alpha create");
|
|
BitmapInfo32__ bi(sz.cx, sz.cy);
|
|
himg = CreateDIBSection(ScreenHDC(), bi, DIB_RGB_COLORS, (void **)§ion, NULL, 0);
|
|
if(!himg) return; // Return on release.
|
|
Copy(section, ~img, (int)img.GetLength());
|
|
}
|
|
LTIMING("Image Alpha blit");
|
|
BLENDFUNCTION bf;
|
|
bf.BlendOp = AC_SRC_OVER;
|
|
bf.BlendFlags = 0;
|
|
bf.SourceConstantAlpha = 255;
|
|
bf.AlphaFormat = AC_SRC_ALPHA;
|
|
HDC dcMem = w.GetCompatibleDC();
|
|
HBITMAP o = (HBITMAP)::SelectObject(dcMem, himg);
|
|
fnAlphaBlend()(dc, x, y, ssz.cx, ssz.cy, dcMem, sr.left, sr.top, ssz.cx, ssz.cy, bf);
|
|
::SelectObject(dcMem, o);
|
|
SysImageRealized(img);
|
|
}
|
|
else {
|
|
LTIMING("Image Alpha sw");
|
|
DrawSurface sf(w, x, y, ssz.cx, ssz.cy);
|
|
RGBA *t = sf;
|
|
if(w.IsPrinter()) // We have got here because printer does not support alpha blending
|
|
Fill(t, White(), ssz.cx * ssz.cy);
|
|
for(int i = sr.top; i < sr.bottom; i++) {
|
|
if(IsNull(c))
|
|
AlphaBlendOpaque(t, img[i] + sr.left, ssz.cx);
|
|
else
|
|
AlphaBlendOpaque(t, img[i] + sr.left, ssz.cx, c);
|
|
t += ssz.cx;
|
|
}
|
|
}
|
|
}
|
|
|
|
struct ImageSysDataMaker : LRUCache<ImageSysData, int64>::Maker {
|
|
Image img;
|
|
|
|
virtual int64 Key() const { return img.GetSerialId(); }
|
|
virtual int Make(ImageSysData& object) const { object.Init(img); return (int)img.GetLength(); }
|
|
};
|
|
|
|
void SystemDraw::SysDrawImageOp(int x, int y, const Image& _img, const Rect& src, Color color)
|
|
{
|
|
LLOG("SysDrawImageOp " << img.GetSerialId() << ' ' << img.GetSize());
|
|
|
|
GuiLock __;
|
|
|
|
Image img = _img;
|
|
|
|
if(img.GetLength() == 0)
|
|
return;
|
|
|
|
Size sz = img.GetSize();
|
|
int kind = img.GetKindNoScan();
|
|
if(kind == IMAGE_OPAQUE && !IsNull(color)) {
|
|
DrawRect(x, y, sz.cx, sz.cy, color);
|
|
return;
|
|
}
|
|
if(kind == IMAGE_OPAQUE && (!IsPrinter() || (GetDeviceCaps(GetHandle(), RASTERCAPS) & RC_DIBTODEV)) && src == img.GetSize()) {
|
|
LTIMING("Image Opaque direct set");
|
|
SetSurface(*this, x, y, sz.cx, sz.cy, ~img);
|
|
return;
|
|
}
|
|
|
|
if(!IsNull(color)) { // avoid SW emulation
|
|
img = CachedSetColorKeepAlpha(img, color);
|
|
color = Null;
|
|
}
|
|
|
|
ImageSysDataMaker m;
|
|
static LRUCache<ImageSysData, int64> cache;
|
|
static int Rsz;
|
|
Rsz += (int)img.GetLength();
|
|
if(Rsz > 200 * 200) { // we do not want to do this for each small image painted...
|
|
Rsz = 0;
|
|
cache.Remove([](const ImageSysData& object) { return object.img.GetRefCount() == 1; });
|
|
}
|
|
LLOG("SysImage cache pixels " << cache.GetSize() << ", count " << cache.GetCount());
|
|
sz = Ctrl::GetVirtualScreenArea().GetSize();
|
|
m.img = IsPrinter() && GetDeviceCaps(GetHandle(), NUMCOLORS) == 2 ? Dither(img, 360) : img; // If printer does not support color, dither
|
|
cache.Get(m).Paint(*this, x, y, src, color);
|
|
cache.Shrink(4 * sz.cx * sz.cy, 1000);
|
|
}
|
|
|
|
void ImageDraw::Section::Init(int cx, int cy)
|
|
{
|
|
GuiLock __;
|
|
dc = ::CreateCompatibleDC(ScreenHDC());
|
|
BitmapInfo32__ bi(cx, cy);
|
|
hbmp = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (void **)&pixels, NULL, 0);
|
|
hbmpOld = (HBITMAP) ::SelectObject(dc, hbmp);
|
|
}
|
|
|
|
ImageDraw::Section::~Section()
|
|
{
|
|
GuiLock __;
|
|
::DeleteObject(::SelectObject(dc, hbmpOld));
|
|
::DeleteDC(dc);
|
|
}
|
|
|
|
void ImageDraw::Init()
|
|
{
|
|
GuiLock __;
|
|
rgb.Init(size.cx, size.cy);
|
|
a.Init(size.cx, size.cy);
|
|
Attach(rgb.dc);
|
|
InitClip(size);
|
|
alpha.Attach(a.dc);
|
|
alpha.InitClip(size);
|
|
has_alpha = false;
|
|
}
|
|
|
|
Draw& ImageDraw::Alpha()
|
|
{
|
|
if(!has_alpha) {
|
|
alpha.DrawRect(size, GrayColor(0));
|
|
has_alpha = true;
|
|
}
|
|
return alpha;
|
|
}
|
|
|
|
Image ImageDraw::Get(bool pm) const
|
|
{
|
|
ImageBuffer b(size);
|
|
int n = size.cx * size.cy;
|
|
memcpy(~b, rgb.pixels, n * sizeof(RGBA));
|
|
const RGBA *s = a.pixels;
|
|
const RGBA *e = a.pixels + n;
|
|
RGBA *t = b;
|
|
if(has_alpha) {
|
|
while(s < e) {
|
|
t->a = s->r;
|
|
t++;
|
|
s++;
|
|
}
|
|
if(pm)
|
|
Premultiply(b);
|
|
b.SetKind(IMAGE_ALPHA);
|
|
}
|
|
else {
|
|
while(s < e) {
|
|
t->a = 255;
|
|
t++;
|
|
s++;
|
|
}
|
|
b.SetKind(IMAGE_OPAQUE);
|
|
}
|
|
return Image(b);
|
|
}
|
|
|
|
ImageDraw::operator Image() const
|
|
{
|
|
return Get(true);
|
|
}
|
|
|
|
Image ImageDraw::GetStraight() const
|
|
{
|
|
return Get(false);
|
|
}
|
|
|
|
ImageDraw::ImageDraw(Size sz)
|
|
{
|
|
size = sz;
|
|
Init();
|
|
}
|
|
|
|
ImageDraw::ImageDraw(int cx, int cy)
|
|
{
|
|
size = Size(cx, cy);
|
|
Init();
|
|
}
|
|
|
|
ImageDraw::~ImageDraw()
|
|
{
|
|
Detach();
|
|
alpha.Detach();
|
|
}
|
|
|
|
#ifdef PLATFORM_WINCE
|
|
|
|
Image Image::Arrow() { return Null; }
|
|
Image Image::Wait() { return Null; }
|
|
Image Image::IBeam() { return Null; }
|
|
Image Image::No() { return Null; }
|
|
Image Image::SizeAll() { return Null; }
|
|
Image Image::SizeHorz() { return Null; }
|
|
Image Image::SizeVert() { return Null; }
|
|
Image Image::SizeTopLeft() { return Null; }
|
|
Image Image::SizeTop() { return Null; }
|
|
Image Image::SizeTopRight() { return Null; }
|
|
Image Image::SizeLeft() { return Null; }
|
|
Image Image::SizeRight() { return Null; }
|
|
Image Image::SizeBottomLeft() { return Null; }
|
|
Image Image::SizeBottom() { return Null; }
|
|
Image Image::SizeBottomRight() { return Null; }
|
|
|
|
#else
|
|
|
|
static Image sWin32Icon(HICON icon, bool cursor)
|
|
{
|
|
GuiLock __;
|
|
ICONINFO iconinfo;
|
|
if(!icon || !GetIconInfo(icon, &iconinfo))
|
|
return Image();
|
|
BITMAP bm;
|
|
::GetObject((HGDIOBJ)iconinfo.hbmMask, sizeof(BITMAP), (LPVOID)&bm);
|
|
HDC dcMem = ::CreateCompatibleDC(NULL);
|
|
Size sz(bm.bmWidth, bm.bmHeight);
|
|
BitmapInfo32__ bi(sz.cx, sz.cy);
|
|
int len = sz.cx * sz.cy;
|
|
Buffer<RGBA> mask(len);
|
|
::SelectObject(dcMem, iconinfo.hbmColor);
|
|
::GetDIBits(dcMem, iconinfo.hbmMask, 0, sz.cy, ~mask, bi, DIB_RGB_COLORS);
|
|
ImageBuffer b(sz.cx, iconinfo.hbmColor ? sz.cy : sz.cy / 2);
|
|
b.SetHotSpot(Point(iconinfo.xHotspot, iconinfo.yHotspot));
|
|
if(iconinfo.hbmColor) {
|
|
::SelectObject(dcMem, iconinfo.hbmColor);
|
|
::GetDIBits(dcMem, iconinfo.hbmColor, 0, sz.cy, ~b, bi, DIB_RGB_COLORS);
|
|
RGBA *s = ~b;
|
|
RGBA *e = s + len;
|
|
RGBA *m = mask;
|
|
while(s < e) {
|
|
if(s->a != 255 && s->a != 0) {
|
|
Premultiply(b);
|
|
goto alpha;
|
|
}
|
|
s++;
|
|
}
|
|
s = ~b;
|
|
while(s < e) {
|
|
s->a = m->r ? 0 : 255;
|
|
s++;
|
|
m++;
|
|
}
|
|
}
|
|
else {
|
|
len /= 2;
|
|
RGBA *s = ~b;
|
|
RGBA *e = s + len;
|
|
RGBA *c = mask + len;
|
|
RGBA *m = mask;
|
|
while(s < e) {
|
|
s->a = (m->r & ~c->r) ? 0 : 255;
|
|
s->r = s->g = s->b = (c->r & ~m->r) ? 255 : 0;
|
|
s++;
|
|
m++;
|
|
c++;
|
|
}
|
|
}
|
|
alpha:
|
|
::DeleteDC(dcMem);
|
|
::DeleteObject(iconinfo.hbmColor);
|
|
::DeleteObject(iconinfo.hbmMask);
|
|
Image img(b);
|
|
::DestroyIcon(icon);
|
|
return img;
|
|
}
|
|
|
|
Image SystemDraw::Win32IconCursor(LPCSTR id, int iconsize, bool cursor)
|
|
{
|
|
HICON icon;
|
|
if(cursor)
|
|
icon = (HICON)LoadCursor(0, id);
|
|
else
|
|
if(iconsize)
|
|
icon = (HICON)LoadImage(GetModuleHandle(NULL), id,
|
|
IMAGE_ICON, iconsize, iconsize, LR_DEFAULTCOLOR);
|
|
else {
|
|
static HRESULT (WINAPI *LoadIconWithScaleDown)(HINSTANCE hinst, PCWSTR pszName, int cx, int cy, HICON *phico);
|
|
ONCELOCK {
|
|
DllFn(LoadIconWithScaleDown, "Comctl32.dll", "LoadIconWithScaleDown");
|
|
}
|
|
|
|
icon = NULL;
|
|
if(LoadIconWithScaleDown)
|
|
LoadIconWithScaleDown(0, (PCWSTR) id, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), &icon);
|
|
else
|
|
icon = LoadIcon(0, id);
|
|
}
|
|
Image img = sWin32Icon(icon, cursor);
|
|
if(cursor)
|
|
img.SetAuxData(reinterpret_cast<uint64>(id));
|
|
return img;
|
|
}
|
|
|
|
Image Win32DllIcon(const char *dll, int ii, bool large)
|
|
{
|
|
HICON icon;
|
|
if(ExtractIconEx(dll, ii, large ? &icon : NULL, large ? NULL : &icon, 1) == 1)
|
|
return sWin32Icon(icon, false);
|
|
return Null;
|
|
}
|
|
|
|
Image Win32Icon(LPCSTR id, int iconsize)
|
|
{
|
|
return SystemDraw::Win32IconCursor(id, iconsize, false);
|
|
}
|
|
|
|
Image Win32Icon(int id, int iconsize)
|
|
{
|
|
return Win32Icon(MAKEINTRESOURCE(id), iconsize);
|
|
}
|
|
|
|
Image Win32Cursor(LPCSTR id)
|
|
{
|
|
return SystemDraw::Win32IconCursor(id, 0, true);
|
|
}
|
|
|
|
Image Win32Cursor(int id)
|
|
{
|
|
return Win32Cursor(MAKEINTRESOURCE(id));
|
|
}
|
|
|
|
HICON SystemDraw::IconWin32(const Image& img_, bool cursor)
|
|
{
|
|
GuiLock __;
|
|
Image img = img_;
|
|
if(img.IsEmpty())
|
|
return NULL;
|
|
if(cursor) {
|
|
LPCSTR id = reinterpret_cast<LPCSTR>(img.GetAuxData());
|
|
if(id)
|
|
return (HICON)LoadCursor(0, id);
|
|
}
|
|
img = Unmultiply(img); // it seems like Win32 wants them unmultiplied...
|
|
Size sz = img.GetSize();
|
|
ICONINFO iconinfo;
|
|
iconinfo.fIcon = !cursor;
|
|
Point p = img.GetHotSpot();
|
|
iconinfo.xHotspot = p.x;
|
|
iconinfo.yHotspot = p.y;
|
|
Size tsz = sz;
|
|
Size csz = Size(min(tsz.cx, sz.cx), min(tsz.cy, sz.cy));
|
|
if(!ImageFallBack) {
|
|
RGBA *pixels;
|
|
BitmapInfo32__ bi(tsz.cx, tsz.cy);
|
|
HDC dcMem = ::CreateCompatibleDC(NULL);
|
|
iconinfo.hbmColor = ::CreateDIBSection(dcMem, bi, DIB_RGB_COLORS, (void **)&pixels, NULL, 0);
|
|
iconinfo.hbmMask = ::CreateBitmap(tsz.cx, tsz.cy, 1, 1, NULL);
|
|
Fill(pixels, RGBAZero(), tsz.cx * tsz.cy);
|
|
for(int y = 0; y < csz.cy; y++)
|
|
memcpy(pixels + y * tsz.cx, img[y], csz.cx * sizeof(RGBA));
|
|
::DeleteDC(dcMem);
|
|
}
|
|
else {
|
|
Buffer<RGBA> h(tsz.cx * tsz.cy);
|
|
HDC dc = ::GetDC(NULL);
|
|
BitmapInfo32__ bi(tsz.cx, tsz.cy);
|
|
iconinfo.hbmMask = CreateBitMask(~img, sz, tsz, csz, h);
|
|
iconinfo.hbmColor = ::CreateDIBitmap(dc, bi, CBM_INIT, h, bi, DIB_RGB_COLORS);
|
|
::ReleaseDC(NULL, dc);
|
|
}
|
|
|
|
HICON icon = ::CreateIconIndirect(&iconinfo);
|
|
::DeleteObject(iconinfo.hbmColor);
|
|
::DeleteObject(iconinfo.hbmMask);
|
|
return icon;
|
|
}
|
|
|
|
#define WCURSOR_(x)\
|
|
{ Image m; INTERLOCKED { static Image img = Win32Cursor(x); m = img; } return m; }
|
|
|
|
Image Image::Arrow() WCURSOR_(IDC_ARROW)
|
|
Image Image::Wait() WCURSOR_(IDC_WAIT)
|
|
Image Image::IBeam() WCURSOR_(IDC_IBEAM)
|
|
Image Image::No() WCURSOR_(IDC_NO)
|
|
Image Image::SizeAll() WCURSOR_(IDC_SIZEALL)
|
|
Image Image::SizeHorz() WCURSOR_(IDC_SIZEWE)
|
|
Image Image::SizeVert() WCURSOR_(IDC_SIZENS)
|
|
Image Image::SizeTopLeft() WCURSOR_(IDC_SIZENWSE)
|
|
Image Image::SizeTop() WCURSOR_(IDC_SIZENS)
|
|
Image Image::SizeTopRight() WCURSOR_(IDC_SIZENESW)
|
|
Image Image::SizeLeft() WCURSOR_(IDC_SIZEWE)
|
|
Image Image::SizeRight() WCURSOR_(IDC_SIZEWE)
|
|
Image Image::SizeBottomLeft() WCURSOR_(IDC_SIZENESW)
|
|
Image Image::SizeBottom() WCURSOR_(IDC_SIZENS)
|
|
Image Image::SizeBottomRight() WCURSOR_(IDC_SIZENWSE)
|
|
Image Image::Cross() WCURSOR_(IDC_CROSS)
|
|
Image Image::Hand() WCURSOR_(IDC_HAND)
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|