Microsoft-3D-Movie-Maker/SETUP/CUSTDLL/SRC/OWNRDRAW.CPP
2022-05-03 16:31:19 -07:00

481 lines
14 KiB
C++

/* Copyright (c) Microsoft Corporation.
Licensed under the MIT License. */
////////////////////////////////////////////////////////////////////////////////
// File: OWNRDRAW.CPP
// Purpose: Sample code for owner draw buttons and lists
////////////////////////////////////////////////////////////////////////////////
#include "ui-hook.h"
static VOID DrawButtonFace(PDRAWITEMSTRUCT pdis, PRECT prc, HBITMAP hbmp);
static VOID DrawRectRgb(HDC, LONG, LONG, LONG, LONG, DWORD);
static VOID BitmapColorTranslate(HDC hdcBits, BITMAP *pbm, DWORD rgb);
static VOID GetButtonColors(HDC hdc);
static LONG CchThisTab(CHAR *pchCur);
static CHAR *PchNextTab(CHAR *pchCur, LONG cch);
static DWORD rgbButtonHighLt;
static DWORD rgbButtonFocus;
static DWORD rgbButtonFace;
static DWORD rgbButtonText;
static DWORD rgbButtonShadow;
#define EraseButton(hwnd,hdc,prc) ExtTextOut(hdc,0,0,ETO_OPAQUE,prc,NULL,0,NULL)
#define rgbWhite RGB(255,255,255)
#define rgbBlack RGB(0,0,0)
#define DPSoa 0x00A803A9L
#define DSPDxax 0x00E20746L
#define BEVEL 2
#define FRAME 1
BOOL PUBLIC FRunningChicagoUI( VOID )
{
DWORD dwVersion = GetVersion();
return ( ((LOWORD(dwVersion) & 0x00ff) >= 0x0004) );
}
////////////////////////////////////////////////////////////////////////////////
// Purpose:
// Draws the button
// Arguments:
// pdis - draw item struct for the button
// hbmp - handle to bitmap to use
////////////////////////////////////////////////////////////////////////////////
VOID DrawButton(PDRAWITEMSTRUCT pdis, HBITMAP hbmp)
{
RECT rc;
LONG dx;
LONG dy;
HBRUSH hbr;
LONG i;
LONG iFrame,
iBevel;
GetButtonColors(pdis->hDC);
SetBkColor(pdis->hDC, GetSysColor(COLOR_WINDOW));
hbr =(HBRUSH)SendMessage(GetParent(pdis->hwndItem), WM_CTLCOLORBTN,
(WPARAM)pdis->hDC, (LPARAM)pdis->hwndItem);
FillRect(pdis->hDC, &pdis->rcItem, hbr);
rc = pdis->rcItem;
dx = rc.right - rc.left;
dy = rc.bottom - rc.top;
iFrame = FRAME;
iBevel = BEVEL;
if (pdis->itemState & ODS_FOCUS)
iFrame *= 2;
// Paint Frame.
if (FRunningChicagoUI())
{
iBevel /= 2;
if (pdis->itemState & ODS_FOCUS)
{
DrawRectRgb(pdis->hDC, rc.left + 1, rc.top + 1, dx, 1, rgbBlack);
DrawRectRgb(pdis->hDC, rc.left + 1, rc.top + 2, 1, dy - 1, rgbBlack);
}
if (pdis->itemState & ODS_SELECTED)
{
DrawRectRgb(pdis->hDC, rc.left + 1, rc.bottom - 1, dx - 1, 1, rgbBlack);
DrawRectRgb(pdis->hDC, rc.right - 1, rc.top + 1, 1, dy - 1, rgbBlack);
}
else
{
DrawRectRgb(pdis->hDC, rc.left + 1, rc.bottom - iFrame, dx - 1, iFrame, rgbBlack);
DrawRectRgb(pdis->hDC, rc.right - iFrame, rc.top + 1, iFrame, dy - 1, rgbBlack);
}
}
else
{
DrawRectRgb(pdis->hDC, rc.left + 1, rc.top, dx - 2, iFrame, rgbBlack);
DrawRectRgb(pdis->hDC, rc.left, rc.top + 1, iFrame, dy - 2, rgbBlack);
DrawRectRgb(pdis->hDC, rc.left + 1, rc.bottom - iFrame, dx - 2, iFrame, rgbBlack);
DrawRectRgb(pdis->hDC, rc.right - iFrame, rc.top + 1, iFrame, dy - 2, rgbBlack);
}
InflateRect(&rc, -iFrame, -iFrame);
dx = rc.right - rc.left;
dy = rc.bottom - rc.top;
SetBkColor(pdis->hDC, rgbButtonFace);
// Paint Shadow.
if (pdis->itemState & ODS_SELECTED)
{
DrawRectRgb(pdis->hDC, rc.left, rc.top, 1, dy, rgbButtonShadow);
DrawRectRgb(pdis->hDC, rc.left, rc.top, dx, 1, rgbButtonShadow);
if (FRunningChicagoUI())
{
DrawRectRgb(pdis->hDC, rc.right, rc.top, 1, dy + 1, rgbButtonShadow);
DrawRectRgb(pdis->hDC, rc.left, rc.bottom, dx + 1, 1, rgbButtonShadow);
}
rc.left += iBevel * 2;
rc.top += iBevel * 2;
}
else
{
for (i = 0; i < iBevel; i++)
{
DrawRectRgb(pdis->hDC, rc.right - 1, rc.top, 1, dy, rgbButtonShadow);
DrawRectRgb(pdis->hDC, rc.left, rc.bottom - 1, dx, 1, rgbButtonShadow);
DrawRectRgb(pdis->hDC, rc.left, rc.top, 1, dy, rgbButtonHighLt);
DrawRectRgb(pdis->hDC, rc.left, rc.top, dx, 1, rgbButtonHighLt);
InflateRect(&rc, -1, -1);
dx -= 2;
dy -= 2;
}
}
if (FRunningChicagoUI())
{
/* On Win95 iBevel is 1/2 as big, so we have to shrink the
* rect some more to keep the same size button face area.
*/
InflateRect(&rc, -iBevel, -iBevel);
}
SetBkColor(pdis->hDC, rgbButtonFace);
if (pdis->itemState & ODS_FOCUS)
SetTextColor(pdis->hDC, rgbButtonFocus);
else
SetTextColor(pdis->hDC, rgbButtonText);
DrawButtonFace(pdis, &rc, hbmp);
}
////////////////////////////////////////////////////////////////////////////////
// Purpose:
// Renders the bitmap on the button
// Arguments:
// pdis - draw item struct for the button
// prc - rectangle to centre bitmap on
// hbmp - handle to bitmap to use
////////////////////////////////////////////////////////////////////////////////
static VOID DrawButtonFace(PDRAWITEMSTRUCT pdis, PRECT prc, HBITMAP hbmp)
{
RECT rc;
HDC hdcBits;
BITMAP bm;
BOOL fMono;
rc = *prc;
IntersectClipRect(pdis->hDC, prc->left, prc->top, prc->right, prc->bottom);
if ((HBITMAP)NULL != hbmp)
{
hdcBits = CreateCompatibleDC(pdis->hDC);
SelectObject(hdcBits, hbmp);
GetObject(hbmp, sizeof bm, (PSTR)&bm);
fMono = (bm.bmPlanes == 1) && (bm.bmBitsPixel == 1);
BitmapColorTranslate(hdcBits, &bm, rgbButtonFace);
LONG iFrame = 1;
if ((pdis->itemState & ODS_FOCUS) == 0)
{
// Shrink rect to defpushbutton size.
InflateRect(&rc, iFrame, iFrame);
iFrame *= 2;
InflateRect(&rc, -iFrame, -iFrame);
}
LONG dx = rc.right - rc.left;
LONG dy = rc.bottom - rc.top;
if (dx < bm.bmWidth || dy < bm.bmHeight)
{
// Scale bitmap to button size.
if (dx * bm.bmHeight < dy * bm.bmWidth)
{
dy = bm.bmHeight * dx / bm.bmWidth;
}
else
{
dx = bm.bmWidth * dy / bm.bmHeight;
}
}
else
{
dx = bm.bmWidth;
dy = bm.bmHeight;
}
// Center it on the button face.
rc.left +=(rc.right - rc.left - dx)/ 2;
rc.top +=(rc.bottom - rc.top - dy)/ 2;
rc.right = rc.left + dx;
rc.bottom = rc.top + dy;
if (pdis->itemState & ODS_DISABLED)
{
// initialize the gray brush
LONG patGray[4];
LONG i;
HBITMAP hbmGray;
HBRUSH hbrGray = (HBRUSH)NULL;
HBRUSH hbrSav = (HBRUSH)NULL;
for (i = 0; i < 4; i++)
patGray[i] = 0xAAAA5555L;
hbmGray = CreateBitmap(8, 8, 1, 1,(LPSTR)patGray);
if ((HBITMAP)NULL != hbmGray)
{
hbrGray = CreatePatternBrush(hbmGray);
DeleteObject(hbmGray);
if ((HBRUSH)NULL != hbrGray)
hbrSav = (HBRUSH)SelectObject(pdis->hDC, hbrGray);
}
SetBkColor(pdis->hDC, RGB(255,255,255));
SetTextColor(pdis->hDC, RGB(0,0,0));
StretchBlt(pdis->hDC, rc.left, rc.top, rc.right - rc.left,
rc.bottom - rc.top, hdcBits, 0, 0, bm.bmWidth,
bm.bmHeight, DPSoa);
if ((HBRUSH)NULL != hbrSav)
SelectObject(pdis->hDC, hbrSav);
if ((HBRUSH)NULL != hbrGray)
DeleteObject(hbrGray);
}
else
{
StretchBlt(pdis->hDC, rc.left, rc.top, rc.right - rc.left,
rc.bottom - rc.top, hdcBits, 0, 0, bm.bmWidth,
bm.bmHeight, SRCCOPY);
}
DeleteDC(hdcBits);
}
}
////////////////////////////////////////////////////////////////////////////////
// Purpose:
// Using the first pixel as the "transparent" colour, make all pixels in the
// hdc that are equal to the "transparent" colour the passed colour.
// Arguments:
// hdcBits - device context for the bitmap
// pbm - pointer to BITMAP struct for the bitmap
// rgb - background colour to show through
////////////////////////////////////////////////////////////////////////////////
static VOID BitmapColorTranslate(HDC hdcBits, BITMAP *pbm, DWORD rgb)
{
HDC hdcMask;
HBITMAP hbmMask;
HBITMAP hbmT;
HBRUSH hbrT;
BOOL fMono;
// is the bitmap mono, or the first pixel is already equal to the
// passed colour? if so we have nothing to do.
fMono = pbm->bmPlanes == 1 && pbm->bmBitsPixel == 1;
if (fMono || GetPixel(hdcBits, 0, 0) == rgb)
return;
// create a mask bitmap and associated DC
hbmMask = CreateBitmap(pbm->bmWidth, pbm->bmHeight, 1, 1, NULL);
if ((HBITMAP)NULL != hbmMask)
{
hdcMask = CreateCompatibleDC(hdcBits);
// select the mask bitmap into the mono DC
hbmT =(HBITMAP)SelectObject(hdcMask, hbmMask);
// create the brush and select it into the bits DC
hbrT =(HBRUSH)SelectObject(hdcBits, CreateSolidBrush(rgb));
// do a colour to mono bitblt to build the mask
// generate 1's where the source is equal to the background is
SetBkColor(hdcBits, GetPixel(hdcBits, 0, 0));
BitBlt(hdcMask, 0, 0, pbm->bmWidth, pbm->bmHeight, hdcBits, 0, 0,
SRCCOPY);
// where the mask is 1 lay down the brush,
// where it is 0 leave the desitnation
SetBkColor(hdcBits, RGB(255,255,255));
SetTextColor(hdcBits, RGB(0,0,0));
BitBlt(hdcBits, 0, 0, pbm->bmWidth, pbm->bmHeight, hdcMask, 0, 0,
DSPDxax);
DeleteObject(SelectObject(hdcBits, hbrT));
DeleteObject(SelectObject(hdcMask, hbmT));
DeleteDC(hdcMask);
}
}
////////////////////////////////////////////////////////////////////////////////
// Purpose:
// Fast Solid draw using ExtTextOut
// Arguments:
// hdc - device context to draw into
// x,y,dx,dy - rectangle to bound solid colour
// rgb - colour to draw
////////////////////////////////////////////////////////////////////////////////
static VOID DrawRectRgb(HDC hdc, LONG x, LONG y, LONG dx, LONG dy, DWORD rgb)
{
RECT rc;
SetBkColor(hdc, rgb);
rc.left = x;
rc.top = y;
rc.right = x + dx;
rc.bottom = y + dy;
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
}
////////////////////////////////////////////////////////////////////////////////
// Purpose:
// intialize colour values for bitmap buttons.
// Arguments:
// hdc - device context to use when initializing colour values
////////////////////////////////////////////////////////////////////////////////
static VOID GetButtonColors(HDC hdc)
{
rgbButtonHighLt = GetSysColor(COLOR_BTNHIGHLIGHT);
rgbButtonFace = GetNearestColor(hdc, GetSysColor(COLOR_BTNFACE)) & 0x00FFFFFFL;
rgbButtonShadow = GetNearestColor(hdc, GetSysColor(COLOR_BTNSHADOW)) & 0x00FFFFFFL;
rgbButtonText = GetNearestColor(hdc, GetSysColor(COLOR_BTNTEXT)) & 0x00FFFFFFL;
rgbButtonFocus = GetNearestColor(hdc, RGB(255,255,255)) & 0x00FFFFFFL;
if (rgbButtonFocus == rgbButtonFace)
rgbButtonFocus = rgbButtonText;
}
////////////////////////////////////////////////////////////////////////////////
// Purpose:
// Draws the button
// Arguments:
// pdis - draw item struct for the button
// ctab - number of tabstops
// prgtab - array of TAB structs for each tabstop
////////////////////////////////////////////////////////////////////////////////
VOID DrawList(PDRAWITEMSTRUCT pdis, LONG ctab, PTAB prgtab, BOOL fCombo)
{
HFONT hfont;
HFONT hfontSav;
COLORREF rgbTextOld;
COLORREF rgbBkgrndOld;
RECT rc;
CHAR *pchT;
CHAR rgch[cbMaxSz];
TEXTMETRIC tm;
LONG y;
LONG itab;
LONG cchT;
if (-1 != pdis->itemID)
SendMessage(pdis->hwndItem, fCombo ? CB_GETLBTEXT : LB_GETTEXT,
pdis->itemID, (LPARAM)rgch);
else
rgch[0] = '\0';
rgbTextOld = SetTextColor(pdis->hDC, GetNearestColor(pdis->hDC,
GetSysColor(pdis->itemState & ODS_SELECTED ? COLOR_HIGHLIGHTTEXT :
COLOR_WINDOWTEXT)) & 0x00FFFFFFL);
rgbBkgrndOld = SetBkColor(pdis->hDC, GetNearestColor(pdis->hDC,
GetSysColor(pdis->itemState & ODS_SELECTED ? COLOR_HIGHLIGHT :
COLOR_WINDOW)) & 0x00FFFFFFL);
if ((HFONT)NULL !=
(hfont = (HFONT)SendMessage(pdis->hwndItem, WM_GETFONT, 0, 0L)))
{
hfontSav = (HFONT)SelectObject(pdis->hDC, hfont);
}
pchT = rgch;
rc = pdis->rcItem;
// clear the whole rc to ensure erased
ExtTextOut(pdis->hDC, rc.left, rc.top, ETO_CLIPPED | ETO_OPAQUE, &rc,
NULL, 0, (LPINT)NULL);
GdiFlush();
GetTextMetrics(pdis->hDC, &tm);
if (tm.tmHeight > rc.bottom - rc.top)
y = rc.top;
else
y = (rc.top + rc.bottom - tm.tmHeight) / 2;
for (itab = 0; itab < ctab; itab++)
{
RECT rcT;
LONG x;
UINT ta;
UINT taSav;
cchT = CchThisTab(pchT);
rc.right = rc.left + prgtab[itab].dx * LOWORD(GetDialogBaseUnits());
IntersectRect(&rcT, &rc, &pdis->rcItem);
switch (prgtab[itab].ttab)
{
case ttabLeft:
x = rc.left;
ta = TA_LEFT;
break;
case ttabRight:
x = rc.right;
ta = TA_RIGHT;
break;
case ttabCentre:
x = rc.left;
ta = TA_CENTER;
break;
}
taSav = SetTextAlign(pdis->hDC, ta);
ExtTextOut(pdis->hDC, x, y, ETO_CLIPPED | ETO_OPAQUE, &rcT,
pchT, cchT, (LPINT)NULL);
SetTextAlign(pdis->hDC, taSav);
GdiFlush();
pchT = PchNextTab(pchT, cchT);
rc.left = rc.right;
}
if (pdis->itemState & ODS_FOCUS)
{
DrawFocusRect(pdis->hDC, &pdis->rcItem);
}
if ((HFONT)NULL != hfontSav)
SelectObject(pdis->hDC, hfontSav);
SetTextColor(pdis->hDC, rgbTextOld);
SetBkColor(pdis->hDC, rgbBkgrndOld);
}
////////////////////////////////////////////////////////////////////////////////
// Purpose:
// Determines the number of characters until the next tab stop
// Arguments:
// prgch - pointer to the array of characters
// pchCur - pointer to the current place in the array
////////////////////////////////////////////////////////////////////////////////
static LONG CchThisTab(CHAR *pchCur)
{
LONG cch;
cch = 0;
while ('\t' != *pchCur && '\0' != *pchCur)
{
pchCur++;
cch++;
}
return cch;
}
////////////////////////////////////////////////////////////////////////////////
// Purpose:
// Returns the character pointer for the next tab stop
// Arguments:
// prgch - pointer to the array of characters
// pchCur - pointer to the current place in the array
////////////////////////////////////////////////////////////////////////////////
static CHAR *PchNextTab(CHAR *pchCur, LONG cch)
{
pchCur += cch;
if ('\t' == *pchCur)
pchCur++;
return pchCur;
}