1320 lines
35 KiB
C
1320 lines
35 KiB
C
#include "ctlspriv.h"
|
|
#pragma hdrstop
|
|
#include "usrctl32.h"
|
|
#include "static.h"
|
|
#include "image.h"
|
|
|
|
#define SS_TEXTMIN1 0x0000000BL
|
|
#define SS_TEXTMAX1 0x0000000DL
|
|
#define SS_EDITCONTROL 0x00002000L
|
|
|
|
#define ISSSTEXTOROD(bType) \
|
|
(((bType) <= SS_TEXTMAX0) \
|
|
|| (((bType) >= SS_TEXTMIN1) \
|
|
&& ((bType) <= SS_TEXTMAX1)))
|
|
|
|
// Common macros for image handling.
|
|
#define IsValidImage(imageType, realType, max) \
|
|
((imageType < max) && (rgbType[imageType] == realType))
|
|
|
|
|
|
//---------------------------------------------------------------------------//
|
|
//
|
|
// Type table. This is used for validation of the
|
|
// image-types. For the PPC release we won't support
|
|
// the metafile format, but others are OK.
|
|
#define IMAGE_STMMAX IMAGE_ENHMETAFILE+1
|
|
static BYTE rgbType[IMAGE_STMMAX] =
|
|
{
|
|
SS_BITMAP, // IMAGE_BITMAP
|
|
SS_ICON, // IMAGE_CURSOR
|
|
SS_ICON, // IMAGE_ICON
|
|
SS_ENHMETAFILE // IMAGE_ENHMETAFILE
|
|
};
|
|
|
|
|
|
//---------------------------------------------------------------------------//
|
|
//
|
|
// LOBYTE of SS_ style is index into this array
|
|
#define STK_OWNER 0x00
|
|
#define STK_IMAGE 0x01
|
|
#define STK_TEXT 0x02
|
|
#define STK_GRAPHIC 0x03
|
|
#define STK_TYPE 0x03
|
|
|
|
#define STK_ERASE 0x04
|
|
#define STK_USEFONT 0x08
|
|
#define STK_USETEXT 0x10
|
|
|
|
BYTE rgstk[] =
|
|
{
|
|
STK_TEXT | STK_ERASE | STK_USEFONT | STK_USETEXT, // SS_LEFT
|
|
STK_TEXT | STK_ERASE | STK_USEFONT | STK_USETEXT, // SS_CENTER
|
|
STK_TEXT | STK_ERASE | STK_USEFONT | STK_USETEXT, // SS_RIGHT
|
|
STK_IMAGE | STK_ERASE, // SS_ICON
|
|
STK_GRAPHIC, // SS_BLACKRECT
|
|
STK_GRAPHIC, // SS_GRAYRECT
|
|
STK_GRAPHIC, // SS_WHITERECT
|
|
STK_GRAPHIC, // SS_BLACKFRAME
|
|
STK_GRAPHIC, // SS_GRAYFRAME
|
|
STK_GRAPHIC, // SS_WHITEFRAME
|
|
STK_OWNER, // SS_USERITEM
|
|
STK_TEXT | STK_USEFONT | STK_USETEXT, // SS_SIMPLE
|
|
STK_TEXT | STK_ERASE | STK_USEFONT | STK_USETEXT, // SS_LEFTNOWORDWRAP
|
|
STK_OWNER | STK_USEFONT | STK_USETEXT, // SS_OWNERDRAW
|
|
STK_IMAGE | STK_ERASE, // SS_BITMAP
|
|
STK_IMAGE | STK_ERASE, // SS_ENHMETAFILE
|
|
STK_GRAPHIC, // SS_ETCHEDHORZ
|
|
STK_GRAPHIC, // SS_ETCHEDVERT
|
|
STK_GRAPHIC // SS_ETCHEDFRAME
|
|
};
|
|
|
|
//---------------------------------------------------------------------------//
|
|
//
|
|
// InitStaticClass() - Registers the control's window class
|
|
//
|
|
BOOL InitStaticClass(HINSTANCE hInstance)
|
|
{
|
|
WNDCLASS wc;
|
|
|
|
wc.lpfnWndProc = Static_WndProc;
|
|
wc.lpszClassName = WC_STATIC;
|
|
wc.style = CS_GLOBALCLASS | CS_PARENTDC | CS_DBLCLKS;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = sizeof(PSTAT);
|
|
wc.hInstance = hInstance;
|
|
wc.hIcon = NULL;
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = NULL;
|
|
wc.lpszMenuName = NULL;
|
|
|
|
if (!RegisterClass(&wc) && !GetClassInfo(hInstance, WC_STATIC, &wc))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------//
|
|
void GetRectInParent(HWND hwnd, PRECT prc)
|
|
{
|
|
HWND hwndParent = GetParent(hwnd);
|
|
|
|
GetWindowRect(hwnd, prc);
|
|
ScreenToClient(hwndParent, (PPOINT)prc);
|
|
ScreenToClient(hwndParent, (PPOINT)&prc->right);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------//
|
|
VOID GetIconSize(HICON hIcon, PSIZE pSize)
|
|
{
|
|
ICONINFO iconInfo;
|
|
BITMAP bmp;
|
|
|
|
pSize->cx = pSize->cy = 32;
|
|
|
|
if (GetIconInfo(hIcon, &iconInfo))
|
|
{
|
|
if (GetObject(iconInfo.hbmColor, sizeof(bmp), &bmp))
|
|
{
|
|
pSize->cx = bmp.bmWidth;
|
|
pSize->cy = bmp.bmHeight;
|
|
}
|
|
|
|
DeleteObject(iconInfo.hbmMask);
|
|
DeleteObject(iconInfo.hbmColor);
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------//
|
|
//
|
|
// SetStaticImage()
|
|
//
|
|
// Sets bitmap/icon of static guy, either in response to a STM_SETxxxx
|
|
// message, or at create time.
|
|
//
|
|
HANDLE Static_SetImage(PSTAT pstat, HANDLE hImage, BOOL fDeleteIt)
|
|
{
|
|
UINT bType;
|
|
RECT rc;
|
|
RECT rcWindow;
|
|
RECT rcClient;
|
|
HANDLE hImageOld;
|
|
DWORD dwRate;
|
|
UINT cicur;
|
|
BOOL fAnimated = FALSE;
|
|
HWND hwnd = pstat->hwnd;
|
|
LONG dwStyle = GET_STYLE(pstat);
|
|
|
|
bType = dwStyle & SS_TYPEMASK;
|
|
|
|
GetClientRect(hwnd, &rcClient);
|
|
|
|
//
|
|
// If this is an old-ani-icon, then delete its timer.
|
|
//
|
|
if ((bType == SS_ICON) && pstat->cicur > 1)
|
|
{
|
|
//
|
|
// Old cursor was an animated cursor, so kill
|
|
// the timer that is used to animate it.
|
|
//
|
|
KillTimer(hwnd, IDSYS_STANIMATE);
|
|
}
|
|
|
|
//
|
|
// Initialize the old-image return value.
|
|
//
|
|
hImageOld = pstat->hImage;
|
|
|
|
rc.right = rc.bottom = 0;
|
|
|
|
if (hImage != NULL)
|
|
{
|
|
|
|
switch (bType)
|
|
{
|
|
case SS_ENHMETAFILE:
|
|
{
|
|
//
|
|
// We do NOT resize the window.
|
|
//
|
|
rc.right = rcClient.right - rcClient.left;
|
|
rc.bottom = rcClient.bottom - rcClient.top;
|
|
|
|
break;
|
|
}
|
|
|
|
case SS_BITMAP:
|
|
{
|
|
BITMAP bmp;
|
|
|
|
pstat->fAlphaImage = FALSE;
|
|
|
|
if (GetObject(hImage, sizeof(BITMAP), &bmp))
|
|
{
|
|
rc.right = bmp.bmWidth;
|
|
rc.bottom = bmp.bmHeight;
|
|
|
|
if (bmp.bmBitsPixel == 32)
|
|
{
|
|
HDC hdc = CreateCompatibleDC(NULL);
|
|
if (hdc)
|
|
{
|
|
RGBQUAD* prgb;
|
|
HBITMAP hbmpImage32 = CreateDIB(hdc, bmp.bmWidth, bmp.bmHeight, &prgb);
|
|
if (hbmpImage32)
|
|
{
|
|
HDC hdc32 = CreateCompatibleDC(hdc);
|
|
if (hdc32)
|
|
{
|
|
HBITMAP hbmpOld = (HBITMAP)SelectObject(hdc32, hbmpImage32);
|
|
HBITMAP hbmpTemp = (HBITMAP)SelectObject(hdc, hImage);
|
|
BitBlt(hdc32, 0, 0, bmp.bmWidth, bmp.bmHeight, hdc, 0, 0, SRCCOPY);
|
|
|
|
SelectObject(hdc, hbmpTemp);
|
|
SelectObject(hdc32, hbmpOld);
|
|
DeleteDC(hdc32);
|
|
|
|
if (DIBHasAlpha(bmp.bmWidth, bmp.bmHeight, prgb))
|
|
{
|
|
PreProcessDIB(bmp.bmWidth, bmp.bmHeight, prgb);
|
|
|
|
if (fDeleteIt)
|
|
DeleteObject(hImage);
|
|
|
|
pstat->fAlphaImage = TRUE;
|
|
hImage = hbmpImage32;
|
|
hbmpImage32 = NULL;
|
|
fDeleteIt = TRUE;
|
|
}
|
|
}
|
|
|
|
if (hbmpImage32)
|
|
DeleteObject(hbmpImage32);
|
|
}
|
|
|
|
DeleteDC(hdc);
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case SS_ICON:
|
|
{
|
|
SIZE size;
|
|
|
|
GetIconSize((HICON)hImage, &size);
|
|
rc.right = size.cx;
|
|
rc.bottom = size.cy;
|
|
|
|
pstat->cicur = 0;
|
|
pstat->iicur = 0;
|
|
|
|
//
|
|
// Perhaps we can do something like shell\cpl\main\mouseptr.c
|
|
// here, and make GetCursorFrameInfo obsolete.
|
|
//
|
|
if (GetCursorFrameInfo(hImage, NULL, 0, &dwRate, &cicur))
|
|
{
|
|
fAnimated = (cicur > 1);
|
|
pstat->cicur = cicur;
|
|
}
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
pstat->hImage = hImage;
|
|
pstat->fDeleteIt = fDeleteIt;
|
|
|
|
//
|
|
// Resize static to fit.
|
|
// Do NOT do this for SS_CENTERIMAGE or SS_REALSIZECONTROL
|
|
//
|
|
if (!(dwStyle & SS_CENTERIMAGE) && !(dwStyle & SS_REALSIZECONTROL))
|
|
{
|
|
//
|
|
// Get current window rect in parent's client coordinates.
|
|
//
|
|
GetRectInParent(hwnd, &rcWindow);
|
|
|
|
//
|
|
// Get new window dimensions
|
|
//
|
|
rc.left = 0;
|
|
rc.top = 0;
|
|
|
|
if (rc.right && rc.bottom)
|
|
{
|
|
AdjustWindowRectEx(&rc, dwStyle, FALSE, GET_EXSTYLE(pstat));
|
|
rc.right -= rc.left;
|
|
rc.bottom -= rc.top;
|
|
}
|
|
|
|
SetWindowPos(hwnd, HWND_TOP,
|
|
0, 0, rc.right, rc.bottom,
|
|
SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
|
|
}
|
|
|
|
if (IsWindowVisible(hwnd))
|
|
{
|
|
InvalidateRect(hwnd, NULL, TRUE);
|
|
UpdateWindow(hwnd);
|
|
}
|
|
|
|
|
|
//
|
|
// If this is an aimated-icon, then start the timer for
|
|
// the animation sequence.
|
|
//
|
|
if(fAnimated)
|
|
{
|
|
//
|
|
// Perhaps we can do something like shell\cpl\main\mouseptr.c
|
|
// here, and make GetCursorFrameInfo obsolete.
|
|
//
|
|
GetCursorFrameInfo(pstat->hImage, NULL, pstat->iicur, &dwRate, &cicur);
|
|
dwRate = max(200, dwRate * 100 / 6);
|
|
SetTimer(hwnd, IDSYS_STANIMATE, dwRate, NULL);
|
|
}
|
|
|
|
return hImageOld;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------//
|
|
//
|
|
// Static_LoadImage()
|
|
//
|
|
// Loads the icon or bitmap from the app's resource file if a name was
|
|
// specified in the dialog template. We assume that the name is the name
|
|
// of the resource to load.
|
|
//
|
|
VOID Static_LoadImage(PSTAT pstat, LPTSTR lpszName)
|
|
{
|
|
HANDLE hImage = NULL;
|
|
HWND hwnd = pstat->hwnd;
|
|
ULONG ulStyle = GET_STYLE(pstat);
|
|
HINSTANCE hInstance = (HINSTANCE) GetWindowInstance(hwnd);
|
|
|
|
if (lpszName && *lpszName)
|
|
{
|
|
//
|
|
// Only try to load the icon/bitmap if the string is non null.
|
|
//
|
|
if (*(BYTE *)lpszName == 0xFF)
|
|
{
|
|
lpszName = (TCHAR*)MAKEINTRESOURCE(((LPWORD)lpszName)[1]);
|
|
}
|
|
|
|
//
|
|
// Load the image. If it can't be found in the app, try the
|
|
// display driver.
|
|
//
|
|
if (lpszName)
|
|
{
|
|
switch ((ulStyle & SS_TYPEMASK))
|
|
{
|
|
case SS_BITMAP:
|
|
|
|
hImage = LoadBitmap(hInstance, lpszName);
|
|
|
|
//
|
|
// If the above didn't load it, try loading it from the
|
|
// display driver (hmod == NULL).
|
|
//
|
|
if (hImage == NULL)
|
|
{
|
|
hImage = LoadBitmap(NULL, lpszName);
|
|
}
|
|
|
|
break;
|
|
|
|
case SS_ICON:
|
|
if ((ulStyle & SS_REALSIZEIMAGE))
|
|
{
|
|
hImage = LoadImage(hInstance, lpszName, IMAGE_ICON, 0, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
hImage = LoadIcon(hInstance, lpszName);
|
|
|
|
//
|
|
// We will also try to load a cursor-format if the
|
|
// window is a 4.0 compatible. Icons/Cursors are really
|
|
// the same. We don't do this for 3.x apps for the
|
|
// usual compatibility reasons.
|
|
//
|
|
if ((hImage == NULL))
|
|
{
|
|
hImage = LoadCursor(hInstance, lpszName);
|
|
}
|
|
|
|
//
|
|
// If the above didn't load it, try loading it from the
|
|
// display driver (hmod == NULL).
|
|
//
|
|
if (hImage == NULL)
|
|
{
|
|
hImage = LoadIcon(NULL, lpszName);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set the image if it was loaded.
|
|
//
|
|
if (hImage)
|
|
{
|
|
Static_SetImage(pstat, hImage, TRUE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------//
|
|
//
|
|
// Static_DrawStateCB()
|
|
//
|
|
// Draws text statics, called by DrawState.
|
|
//
|
|
BOOL CALLBACK Static_DrawStateCB(HDC hdc, LPARAM lp, WPARAM wp, int cx, int cy)
|
|
{
|
|
PSTAT pstat = (PSTAT)lp;
|
|
if (pstat)
|
|
{
|
|
UINT style;
|
|
RECT rc;
|
|
BYTE bType;
|
|
LONG lTextLength;
|
|
ULONG ulStyle = GET_STYLE(pstat);
|
|
ULONG ulExStyle = GET_EXSTYLE(pstat);
|
|
HWND hwnd = pstat->hwnd;
|
|
|
|
|
|
bType = (BYTE)(ulStyle & SS_TYPEMASK);
|
|
|
|
if ((lTextLength = GetWindowTextLength(hwnd)))
|
|
{
|
|
PTCHAR lpszName = (TCHAR *) _alloca((lTextLength + 1) * sizeof(wchar_t));
|
|
|
|
if (lpszName)
|
|
{
|
|
GetWindowText(pstat->hwnd, lpszName, lTextLength + 1);
|
|
style = DT_NOCLIP | DT_EXPANDTABS;
|
|
|
|
if (bType != LOBYTE(SS_LEFTNOWORDWRAP))
|
|
{
|
|
style |= DT_WORDBREAK;
|
|
style |= (UINT)(bType - LOBYTE(SS_LEFT));
|
|
|
|
if (ulStyle & SS_EDITCONTROL)
|
|
{
|
|
style |= DT_EDITCONTROL;
|
|
}
|
|
}
|
|
|
|
switch (ulStyle & SS_ELLIPSISMASK)
|
|
{
|
|
case SS_WORDELLIPSIS:
|
|
style |= DT_WORD_ELLIPSIS | DT_SINGLELINE;
|
|
break;
|
|
|
|
case SS_PATHELLIPSIS:
|
|
style |= DT_PATH_ELLIPSIS | DT_SINGLELINE;
|
|
break;
|
|
|
|
case SS_ENDELLIPSIS:
|
|
style |= DT_END_ELLIPSIS | DT_SINGLELINE;
|
|
break;
|
|
}
|
|
|
|
if (ulStyle & SS_NOPREFIX)
|
|
{
|
|
style |= DT_NOPREFIX;
|
|
}
|
|
|
|
if (ulStyle & SS_CENTERIMAGE)
|
|
{
|
|
style |= DT_VCENTER | DT_SINGLELINE;
|
|
}
|
|
|
|
rc.left = 0;
|
|
rc.top = 0;
|
|
rc.right = cx;
|
|
rc.bottom = cy;
|
|
|
|
if (TESTFLAG(GET_EXSTYLE(pstat), WS_EXP_UIACCELHIDDEN))
|
|
{
|
|
style |= DT_HIDEPREFIX;
|
|
}
|
|
else if (pstat->fPaintKbdCuesOnly)
|
|
{
|
|
style |= DT_PREFIXONLY;
|
|
}
|
|
|
|
if (!pstat->hTheme)
|
|
{
|
|
DrawText(hdc, lpszName, -1, &rc, (DWORD)style);
|
|
}
|
|
else
|
|
{
|
|
DrawThemeText(pstat->hTheme,
|
|
hdc,
|
|
0,
|
|
0,
|
|
lpszName,
|
|
lTextLength,
|
|
style,
|
|
0,
|
|
&rc);
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------//
|
|
void Static_Paint(PSTAT pstat, HDC hdc, BOOL fClip)
|
|
{
|
|
HWND hwndParent;
|
|
RECT rc;
|
|
UINT cmd;
|
|
BYTE bType;
|
|
BOOL fFont;
|
|
HBRUSH hbrControl;
|
|
UINT oldAlign;
|
|
DWORD dwOldLayout=0;
|
|
HANDLE hfontOld = NULL;
|
|
HWND hwnd = pstat->hwnd;
|
|
ULONG ulStyle = GET_STYLE(pstat);
|
|
ULONG ulExStyle = GET_EXSTYLE(pstat);
|
|
|
|
if (ulExStyle & WS_EX_RTLREADING)
|
|
{
|
|
oldAlign = GetTextAlign(hdc);
|
|
SetTextAlign(hdc, oldAlign | TA_RTLREADING);
|
|
}
|
|
|
|
bType = (BYTE)(ulStyle & SS_TYPEMASK);
|
|
GetClientRect(hwnd, &rc);
|
|
|
|
if (fClip)
|
|
{
|
|
IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);
|
|
}
|
|
|
|
fFont = (rgstk[bType] & STK_USEFONT) && (pstat->hFont != NULL);
|
|
|
|
if (fFont)
|
|
{
|
|
hfontOld = SelectObject(hdc, pstat->hFont);
|
|
}
|
|
|
|
//
|
|
// Send WM_CTLCOLORSTATIC to all statics (even frames) for 1.03
|
|
// compatibility.
|
|
//
|
|
SetBkMode(hdc, OPAQUE);
|
|
hbrControl = (HBRUSH)SendMessage(GetParent(hwnd), WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hwnd);
|
|
|
|
//
|
|
// Do we erase the background? We don't for SS_OWNERDRAW
|
|
// and STK_GRAPHIC kind of things.
|
|
//
|
|
hwndParent = GetParent(hwnd);
|
|
|
|
if ((rgstk[bType] & STK_ERASE) &&
|
|
!pstat->fPaintKbdCuesOnly &&
|
|
!pstat->hTheme)
|
|
{
|
|
FillRect(hdc, &rc, hbrControl);
|
|
}
|
|
|
|
switch (LOBYTE(bType))
|
|
{
|
|
case SS_ICON:
|
|
|
|
if (pstat->hImage)
|
|
{
|
|
|
|
int cx;
|
|
int cy;
|
|
|
|
if (ulExStyle & WS_EX_LAYOUTRTL)
|
|
{
|
|
dwOldLayout = SetLayoutWidth(hdc, -1, 0);
|
|
}
|
|
|
|
//
|
|
// Perform the correct rect-setup.
|
|
//
|
|
if (ulStyle & SS_CENTERIMAGE)
|
|
{
|
|
SIZE size;
|
|
|
|
GetIconSize((HICON)pstat->hImage, &size);
|
|
cx = size.cx;
|
|
cy = size.cy;
|
|
|
|
rc.left = (rc.right - cx) / 2;
|
|
rc.right = (rc.left + cx);
|
|
rc.top = (rc.bottom - cy) / 2;
|
|
rc.bottom = (rc.top + cy);
|
|
}
|
|
else
|
|
{
|
|
cx = rc.right - rc.left;
|
|
cy = rc.bottom - rc.top;
|
|
}
|
|
|
|
DrawIconEx(hdc, rc.left, rc.top, (HICON)pstat->hImage, cx, cy,
|
|
pstat->iicur, pstat->hTheme ? NULL : hbrControl, DI_NORMAL);
|
|
|
|
if (ulExStyle & WS_EX_LAYOUTRTL)
|
|
{
|
|
SetLayoutWidth(hdc, -1, dwOldLayout);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Empty! Need to erase.
|
|
FillRect(hdc, &rc, hbrControl);
|
|
}
|
|
break;
|
|
|
|
case SS_BITMAP:
|
|
|
|
if (pstat->hImage)
|
|
{
|
|
|
|
BITMAP bmp;
|
|
//
|
|
// Get the bitmap information. If this fails, then we
|
|
// can assume somethings wrong with its format...don't
|
|
// draw in this case.
|
|
//
|
|
if (GetObject(pstat->hImage, sizeof(BITMAP), &bmp))
|
|
{
|
|
HDC hdcT;
|
|
|
|
if (ulStyle & SS_CENTERIMAGE)
|
|
{
|
|
rc.left = (rc.right - bmp.bmWidth) >> 1;
|
|
rc.right = (rc.left + bmp.bmWidth);
|
|
rc.top = (rc.bottom - bmp.bmHeight) >> 1;
|
|
rc.bottom = (rc.top + bmp.bmHeight);
|
|
}
|
|
|
|
//
|
|
// Select in the bitmap and blt it to the client-surface.
|
|
//
|
|
hdcT = CreateCompatibleDC(hdc);
|
|
if (hdcT)
|
|
{
|
|
HBITMAP hbmpT = (HBITMAP)SelectObject(hdcT, pstat->hImage);
|
|
|
|
if (pstat->fAlphaImage)
|
|
{
|
|
BLENDFUNCTION bf = {0};
|
|
bf.BlendOp = AC_SRC_OVER;
|
|
bf.SourceConstantAlpha = 255;
|
|
bf.AlphaFormat = AC_SRC_ALPHA;
|
|
bf.BlendFlags = 0;
|
|
GdiAlphaBlend(hdc, rc.left, rc.top, rc.right-rc.left,
|
|
rc.bottom-rc.top, hdcT, 0, 0, bmp.bmWidth, bmp.bmHeight, bf);
|
|
}
|
|
else
|
|
{
|
|
// I'm assuming people try to match the color to the dialog
|
|
GdiTransparentBlt(hdc, rc.left, rc.top, rc.right-rc.left,
|
|
rc.bottom-rc.top, hdcT, 0, 0, bmp.bmWidth,
|
|
bmp.bmHeight, GetSysColor(COLOR_BTNFACE));
|
|
}
|
|
|
|
if (hbmpT)
|
|
{
|
|
SelectObject(hdcT, hbmpT);
|
|
}
|
|
|
|
DeleteDC(hdcT);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SS_ENHMETAFILE:
|
|
|
|
if (pstat->hImage)
|
|
{
|
|
RECT rcl;
|
|
|
|
rcl.left = rc.left;
|
|
rcl.top = rc.top;
|
|
rcl.right = rc.right;
|
|
rcl.bottom = rc.bottom;
|
|
|
|
PlayEnhMetaFile(hdc, (HENHMETAFILE)pstat->hImage, &rcl);
|
|
}
|
|
break;
|
|
|
|
case SS_OWNERDRAW:
|
|
{
|
|
DRAWITEMSTRUCT dis;
|
|
|
|
dis.CtlType = ODT_STATIC;
|
|
dis.CtlID = GetDlgCtrlID(hwnd);
|
|
dis.itemAction = ODA_DRAWENTIRE;
|
|
dis.itemState = IsWindowVisible(hwnd) ? ODS_DISABLED : 0;
|
|
dis.hwndItem = hwnd;
|
|
dis.hDC = hdc;
|
|
dis.itemData = 0L;
|
|
dis.rcItem = rc;
|
|
|
|
if (TESTFLAG(GET_EXSTYLE(pstat), WS_EXP_UIACCELHIDDEN))
|
|
{
|
|
dis.itemState |= ODS_NOACCEL;
|
|
}
|
|
|
|
//
|
|
// Send a WM_DRAWITEM message to the parent.
|
|
//
|
|
SendMessage(hwndParent, WM_DRAWITEM, (WPARAM)dis.CtlID, (LPARAM)&dis);
|
|
}
|
|
break;
|
|
|
|
case SS_LEFT:
|
|
case SS_CENTER:
|
|
case SS_RIGHT:
|
|
case SS_LEFTNOWORDWRAP:
|
|
|
|
if (GetWindowTextLength(hwnd))
|
|
{
|
|
UINT dstFlags;
|
|
|
|
dstFlags = DST_COMPLEX;
|
|
|
|
if (!IsWindowEnabled(hwnd))
|
|
{
|
|
dstFlags |= DSS_DISABLED;
|
|
}
|
|
|
|
DrawState(hdc, GetSysColorBrush(COLOR_WINDOWTEXT),
|
|
(DRAWSTATEPROC)Static_DrawStateCB,(LPARAM)pstat, (WPARAM)TRUE,
|
|
rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
|
|
dstFlags);
|
|
}
|
|
break;
|
|
|
|
case SS_SIMPLE:
|
|
{
|
|
LPWSTR pszText = NULL;
|
|
INT cchText;
|
|
|
|
//
|
|
// The "Simple" bType assumes everything, including the following:
|
|
// 1. The Text exists and fits on one line.
|
|
// 2. The Static item is always enabled.
|
|
// 3. The Static item is never changed to be a shorter string.
|
|
// 4. The Parent never responds to the CTLCOLOR message
|
|
//
|
|
cchText = GetWindowTextLength(hwnd);
|
|
if (cchText > 0)
|
|
{
|
|
pszText = (LPWSTR)_alloca((cchText + 1) * sizeof(WCHAR));
|
|
cchText = GetWindowText(hwnd, pszText, cchText + 1);
|
|
}
|
|
else
|
|
{
|
|
pszText = TEXT("");
|
|
cchText = 0;
|
|
}
|
|
|
|
if (pszText)
|
|
{
|
|
if (ulStyle & SS_NOPREFIX && !pstat->hTheme)
|
|
{
|
|
ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE | ETO_CLIPPED, &rc, pszText, cchText, 0L);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Use OPAQUE for speed.
|
|
//
|
|
DWORD dwFlags;
|
|
if (TESTFLAG(GET_EXSTYLE(pstat), WS_EXP_UIACCELHIDDEN))
|
|
{
|
|
dwFlags = DT_HIDEPREFIX;
|
|
}
|
|
else if (pstat->fPaintKbdCuesOnly)
|
|
{
|
|
dwFlags = DT_PREFIXONLY;
|
|
}
|
|
else if (ulStyle & SS_NOPREFIX)
|
|
{
|
|
dwFlags = DT_NOPREFIX;
|
|
}
|
|
else
|
|
{
|
|
dwFlags = 0;
|
|
}
|
|
|
|
if (!pstat->hTheme)
|
|
{
|
|
TextOut(hdc, rc.left, rc.top, pszText, cchText);
|
|
}
|
|
else
|
|
{
|
|
DrawThemeText(pstat->hTheme, hdc, 0, 0, pszText, cchText, dwFlags, 0, &rc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case SS_BLACKFRAME:
|
|
cmd = (COLOR_3DDKSHADOW << 3);
|
|
goto StatFrame;
|
|
|
|
case SS_GRAYFRAME:
|
|
cmd = (COLOR_3DSHADOW << 3);
|
|
goto StatFrame;
|
|
|
|
case SS_WHITEFRAME:
|
|
cmd = (COLOR_3DHILIGHT << 3);
|
|
StatFrame:
|
|
DrawFrame(hdc, &rc, 1, cmd);
|
|
break;
|
|
|
|
case SS_BLACKRECT:
|
|
hbrControl = GetSysColorBrush(COLOR_3DDKSHADOW);
|
|
goto StatRect;
|
|
|
|
case SS_GRAYRECT:
|
|
hbrControl = GetSysColorBrush(COLOR_3DSHADOW);
|
|
goto StatRect;
|
|
|
|
case SS_WHITERECT:
|
|
hbrControl = GetSysColorBrush(COLOR_3DHILIGHT);
|
|
StatRect:
|
|
FillRect(hdc, &rc, hbrControl);
|
|
break;
|
|
|
|
case SS_ETCHEDFRAME:
|
|
DrawEdge(hdc, &rc, EDGE_ETCHED, BF_RECT);
|
|
break;
|
|
}
|
|
|
|
if (hfontOld)
|
|
{
|
|
SelectObject(hdc, hfontOld);
|
|
}
|
|
|
|
if (ulExStyle & WS_EX_RTLREADING)
|
|
{
|
|
SetTextAlign(hdc, oldAlign);
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------//
|
|
void Static_Repaint(PSTAT pstat)
|
|
{
|
|
HWND hwnd = pstat->hwnd;
|
|
|
|
if (IsWindowVisible(hwnd))
|
|
{
|
|
HDC hdc;
|
|
|
|
if (hdc = GetDC(hwnd))
|
|
{
|
|
Static_Paint(pstat, hdc, TRUE);
|
|
ReleaseDC(hwnd, hdc);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------//
|
|
//
|
|
// Static_NotifyParent()
|
|
//
|
|
// Sends WM_COMMAND notification messages.
|
|
//
|
|
LRESULT Static_NotifyParent(HWND hwnd, HWND hwndParent, int nCode)
|
|
{
|
|
LRESULT lret;
|
|
|
|
if (!hwndParent)
|
|
{
|
|
hwndParent = GetParent(hwnd);
|
|
}
|
|
|
|
lret = SendMessage(hwndParent, WM_COMMAND,
|
|
MAKELONG(GetDlgCtrlID(hwnd), nCode), (LPARAM)hwnd);
|
|
|
|
return lret;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------//
|
|
//
|
|
// Static_AniIconStep
|
|
//
|
|
// Advances to the next step in an animaged icon.
|
|
//
|
|
VOID Static_AniIconStep(PSTAT pstat)
|
|
{
|
|
DWORD dwRate;
|
|
HWND hwnd = pstat->hwnd;
|
|
|
|
dwRate = 0;
|
|
|
|
//
|
|
// Stop the timer for the next animation step.
|
|
//
|
|
KillTimer(hwnd, IDSYS_STANIMATE);
|
|
|
|
if (++(pstat->iicur) >= pstat->cicur)
|
|
{
|
|
pstat->iicur = 0;
|
|
}
|
|
|
|
//
|
|
// Perhaps we can do something like shell\cpl\main\mouseptr.c
|
|
// here, and make GetCursorFrameInfo obsolete.
|
|
//
|
|
GetCursorFrameInfo(pstat->hImage, NULL, pstat->iicur, &dwRate, &pstat->cicur);
|
|
dwRate = max(200, dwRate * 100 / 6);
|
|
|
|
InvalidateRect(hwnd, NULL, FALSE);
|
|
UpdateWindow(hwnd);
|
|
|
|
SetTimer(hwnd, IDSYS_STANIMATE, dwRate, NULL);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------//
|
|
//
|
|
// Static_WndProc
|
|
//
|
|
// WndProc for Static controls
|
|
//
|
|
LRESULT APIENTRY Static_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PSTAT pstat;
|
|
LRESULT lReturn = FALSE;
|
|
|
|
//
|
|
// Get the instance data for this static control
|
|
//
|
|
pstat = Static_GetPtr(hwnd);
|
|
if (!pstat && uMsg != WM_NCCREATE)
|
|
{
|
|
goto CallDWP;
|
|
}
|
|
|
|
switch (uMsg)
|
|
{
|
|
case STM_GETICON:
|
|
wParam = IMAGE_ICON;
|
|
|
|
case STM_GETIMAGE:
|
|
if (IsValidImage(wParam, (GET_STYLE(pstat) & SS_TYPEMASK), IMAGE_STMMAX))
|
|
{
|
|
return (LRESULT)pstat->hImage;
|
|
}
|
|
break;
|
|
|
|
case STM_SETICON:
|
|
lParam = (LPARAM)wParam;
|
|
wParam = IMAGE_ICON;
|
|
|
|
case STM_SETIMAGE:
|
|
if (IsValidImage(wParam, (GET_STYLE(pstat) & SS_TYPEMASK), IMAGE_STMMAX))
|
|
{
|
|
return (LRESULT)Static_SetImage(pstat, (HANDLE)lParam, FALSE);
|
|
}
|
|
break;
|
|
|
|
case WM_ERASEBKGND:
|
|
|
|
//
|
|
// The control will be erased in Static_Paint().
|
|
//
|
|
return TRUE;
|
|
|
|
case WM_PRINTCLIENT:
|
|
Static_Paint(pstat, (HDC)wParam, FALSE);
|
|
break;
|
|
|
|
case WM_PAINT:
|
|
{
|
|
HDC hdc;
|
|
PAINTSTRUCT ps;
|
|
|
|
hdc = (HDC)wParam;
|
|
if (hdc == NULL)
|
|
{
|
|
hdc = BeginPaint(hwnd, &ps);
|
|
}
|
|
|
|
if (IsWindowVisible(hwnd))
|
|
{
|
|
Static_Paint(pstat, hdc, !wParam);
|
|
}
|
|
|
|
//
|
|
// If hwnd was destroyed, BeginPaint was automatically undone.
|
|
//
|
|
if (!wParam)
|
|
{
|
|
EndPaint(hwnd, &ps);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case WM_CREATE:
|
|
{
|
|
BYTE bType = (BYTE)(GET_STYLE(pstat) & SS_TYPEMASK);
|
|
pstat->hTheme = OpenThemeData(pstat->hwnd, L"Static");
|
|
EnableThemeDialogTexture(GetParent(pstat->hwnd), ETDT_ENABLE);
|
|
|
|
if ((rgstk[bType] & STK_TYPE) == STK_IMAGE)
|
|
{
|
|
LPTSTR lpszName;
|
|
|
|
lpszName = (LPTSTR)(((LPCREATESTRUCT)lParam)->lpszName);
|
|
|
|
//
|
|
// Load the image
|
|
//
|
|
Static_LoadImage(pstat, lpszName);
|
|
}
|
|
else if (bType == SS_ETCHEDHORZ || bType == SS_ETCHEDVERT)
|
|
{
|
|
//
|
|
// Resize static window to fit edge. Horizontal dudes
|
|
// make bottom one edge from top, vertical dudes make
|
|
// right edge one edge from left.
|
|
//
|
|
RECT rcClient;
|
|
|
|
GetClientRect(hwnd, &rcClient);
|
|
if (bType == SS_ETCHEDHORZ)
|
|
{
|
|
rcClient.bottom = GetSystemMetrics(SM_CYEDGE);
|
|
}
|
|
else
|
|
{
|
|
rcClient.right = GetSystemMetrics(SM_CXEDGE);
|
|
}
|
|
|
|
SetWindowPos(hwnd, HWND_TOP, 0, 0, rcClient.right,
|
|
rcClient.bottom, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
BYTE bType = (BYTE)(GET_STYLE(pstat) & SS_TYPEMASK);
|
|
|
|
if (((rgstk[bType] & STK_TYPE) == STK_IMAGE) &&
|
|
(pstat->hImage != NULL) &&
|
|
(pstat->fDeleteIt))
|
|
{
|
|
|
|
if (bType == SS_BITMAP)
|
|
{
|
|
DeleteObject(pstat->hImage);
|
|
}
|
|
else if (bType == SS_ICON)
|
|
{
|
|
if (pstat->cicur > 1)
|
|
{
|
|
// Kill the animated cursor timer
|
|
KillTimer(hwnd, IDSYS_STANIMATE);
|
|
}
|
|
DestroyIcon((HICON)(pstat->hImage));
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
case WM_NCCREATE:
|
|
|
|
//
|
|
// Allocate the static instance stucture
|
|
//
|
|
pstat = (PSTAT)UserLocalAlloc(HEAP_ZERO_MEMORY, sizeof(STAT));
|
|
if (pstat)
|
|
{
|
|
DWORD dwStyle;
|
|
DWORD dwExStyle;
|
|
BYTE bType;
|
|
|
|
//
|
|
// Success... store the instance pointer.
|
|
//
|
|
TraceMsg(TF_STANDARD, "STATIC: Setting static instance pointer.");
|
|
Static_SetPtr(hwnd, pstat);
|
|
|
|
pstat->hwnd = hwnd;
|
|
pstat->pww = (PWW)GetWindowLongPtr(hwnd, GWLP_WOWWORDS);
|
|
|
|
dwStyle = GET_STYLE(pstat);
|
|
dwExStyle = GET_EXSTYLE(pstat);
|
|
bType = (BYTE)(dwStyle & SS_TYPEMASK);
|
|
|
|
if ((dwExStyle & WS_EX_RIGHT) != 0)
|
|
{
|
|
AlterWindowStyle(hwnd, SS_TYPEMASK, SS_RIGHT);
|
|
}
|
|
|
|
if (dwStyle & SS_SUNKEN ||
|
|
((bType == LOBYTE(SS_ETCHEDHORZ)) || (bType == LOBYTE(SS_ETCHEDVERT))))
|
|
{
|
|
dwExStyle |= WS_EX_STATICEDGE;
|
|
SetWindowLong(hwnd, GWL_EXSTYLE, dwExStyle);
|
|
}
|
|
|
|
|
|
goto CallDWP;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Failed... return FALSE.
|
|
//
|
|
// From a WM_NCCREATE msg, this will cause the
|
|
// CreateWindow call to fail.
|
|
//
|
|
TraceMsg(TF_STANDARD, "STATIC: Unable to allocate static instance structure.");
|
|
lReturn = FALSE;
|
|
}
|
|
|
|
break;
|
|
|
|
case WM_NCDESTROY:
|
|
if ( pstat->hTheme )
|
|
{
|
|
CloseThemeData(pstat->hTheme);
|
|
}
|
|
|
|
UserLocalFree(pstat);
|
|
TraceMsg(TF_STANDARD, "STATIC: Clearing static instance pointer.");
|
|
Static_SetPtr(hwnd, NULL);
|
|
|
|
break;
|
|
|
|
case WM_NCHITTEST:
|
|
return (GET_STYLE(pstat) & SS_NOTIFY) ? HTCLIENT : HTTRANSPARENT;
|
|
|
|
case WM_LBUTTONDOWN:
|
|
case WM_NCLBUTTONDOWN:
|
|
if (GET_STYLE(pstat) & SS_NOTIFY)
|
|
{
|
|
//
|
|
// It is acceptable for an app to destroy a static label
|
|
// in response to a STN_CLICKED notification.
|
|
//
|
|
Static_NotifyParent(hwnd, NULL, STN_CLICKED);
|
|
}
|
|
break;
|
|
|
|
case WM_LBUTTONDBLCLK:
|
|
case WM_NCLBUTTONDBLCLK:
|
|
if (GET_STYLE(pstat) & SS_NOTIFY)
|
|
{
|
|
//
|
|
// It is acceptable for an app to destroy a static label in
|
|
// response to a STN_DBLCLK notification.
|
|
//
|
|
Static_NotifyParent(hwnd, NULL, STN_DBLCLK);
|
|
}
|
|
break;
|
|
|
|
case WM_SETTEXT:
|
|
{
|
|
BYTE bType = (BYTE)(GET_STYLE(pstat) & SS_TYPEMASK);
|
|
|
|
//
|
|
// No more hack to set icon/bitmap via WM_SETTEXT!
|
|
//
|
|
if (rgstk[bType] & STK_USETEXT)
|
|
{
|
|
if (DefWindowProc(hwnd, WM_SETTEXT, wParam, lParam))
|
|
{
|
|
Static_Repaint(pstat);
|
|
return TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
}
|
|
case WM_ENABLE:
|
|
Static_Repaint(pstat);
|
|
if (GET_STYLE(pstat) & SS_NOTIFY)
|
|
{
|
|
Static_NotifyParent(hwnd, NULL, (wParam ? STN_ENABLE : STN_DISABLE));
|
|
}
|
|
break;
|
|
|
|
case WM_GETDLGCODE:
|
|
return (LONG)DLGC_STATIC;
|
|
|
|
case WM_SETFONT:
|
|
{
|
|
BYTE bType = (BYTE)(GET_STYLE(pstat) & SS_TYPEMASK);
|
|
|
|
//
|
|
// wParam - handle to the font
|
|
// lParam - if true, redraw else don't
|
|
//
|
|
if (rgstk[bType] & STK_USEFONT)
|
|
{
|
|
pstat->hFont = (HANDLE)wParam;
|
|
|
|
if (lParam && IsWindowVisible(hwnd))
|
|
{
|
|
InvalidateRect(hwnd, NULL, TRUE);
|
|
UpdateWindow(hwnd);
|
|
}
|
|
}
|
|
break;
|
|
|
|
}
|
|
case WM_GETFONT:
|
|
{
|
|
BYTE bType = (BYTE)(GET_STYLE(pstat) & SS_TYPEMASK);
|
|
|
|
if (rgstk[bType] & STK_USEFONT)
|
|
{
|
|
return (LRESULT)pstat->hFont;
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
case WM_TIMER:
|
|
if (wParam == IDSYS_STANIMATE)
|
|
{
|
|
Static_AniIconStep(pstat);
|
|
}
|
|
break;
|
|
|
|
case WM_UPDATEUISTATE:
|
|
{
|
|
DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
|
|
if (HIWORD(wParam) & UISF_HIDEACCEL)
|
|
{
|
|
BYTE bType = (BYTE)(GET_STYLE(pstat) & SS_TYPEMASK);
|
|
|
|
if (ISSSTEXTOROD(bType))
|
|
{
|
|
pstat->fPaintKbdCuesOnly = TRUE;
|
|
Static_Repaint(pstat);
|
|
pstat->fPaintKbdCuesOnly = FALSE;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_GETOBJECT:
|
|
|
|
if(lParam == OBJID_QUERYCLASSNAMEIDX)
|
|
{
|
|
lReturn = MSAA_CLASSNAMEIDX_STATIC;
|
|
}
|
|
else
|
|
{
|
|
lReturn = FALSE;
|
|
}
|
|
|
|
break;
|
|
|
|
case WM_THEMECHANGED:
|
|
|
|
if ( pstat->hTheme )
|
|
{
|
|
CloseThemeData(pstat->hTheme);
|
|
}
|
|
|
|
pstat->hTheme = OpenThemeData(pstat->hwnd, L"Static");
|
|
|
|
InvalidateRect(pstat->hwnd, NULL, TRUE);
|
|
|
|
lReturn = TRUE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
CallDWP:
|
|
lReturn = DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
return lReturn;
|
|
}
|