reactos/rosapps/smartpdf/baseutils/ms_ui_helper.c
Klemens Friedl 435a566751 SmartPDF - lightweight pdf viewer app for rosapps
* sumatrapdf - vendor import
* everything compiles (libjpeg, poppler, fitz, sumatrapdf)
* does NOT link

(remove the comment tags in the parent directory.rbuild file (rosapps dir) to build it)

svn path=/trunk/; revision=29295
2007-09-29 08:39:35 +00:00

635 lines
17 KiB
C

/*++
Copyright (c) 2003 Microsoft Corporation
Abstract:
Helper functions for HIDPI/Landscape support.
--*/
#include "ms_ui_helper.h"
HIDPI_ENABLE;
BOOL HIDPI_StretchBitmap(
HBITMAP* phbm,
int cxDstImg,
int cyDstImg,
int cImagesX,
int cImagesY
)
{
BOOL fRet = FALSE;
HBITMAP hbmNew;
BITMAP bm;
HDC hdcSrc, hdcDst, hdcScreen;
HBITMAP hbmOldSrc, hbmOldDst;
int cxSrcImg, cySrcImg;
int i, j, xDest, yDest, xBmp, yBmp;
if (!phbm || !*phbm || (cxDstImg == 0 && cyDstImg == 0) || (cImagesX == 0 || cImagesY == 0))
goto donestretch;
if ((sizeof(bm) != GetObject(*phbm, sizeof(bm), &bm)))
goto donestretch;
// If you hit this ASSERT, that mean your passed in image count in row and
// the column number of images is not correct.
// ASSERT(((bm.bmWidth % cImagesX) == 0) && ((bm.bmHeight % cImagesY) == 0));
cxSrcImg = bm.bmWidth / cImagesX;
cySrcImg = bm.bmHeight / cImagesY;
if (cxSrcImg == cxDstImg && cySrcImg == cyDstImg)
{
fRet = TRUE;
goto donestretch;
}
if (cxDstImg == 0)
cxDstImg = HIDPIMulDiv(cyDstImg, cxSrcImg, cySrcImg);
else if (cyDstImg == 0)
cyDstImg = HIDPIMulDiv(cxDstImg, cySrcImg, cxSrcImg);
hdcSrc = CreateCompatibleDC(NULL);
hdcDst = CreateCompatibleDC(NULL);
hdcScreen = GetDC(NULL);
hbmOldSrc = (HBITMAP)SelectObject(hdcSrc, *phbm);
hbmNew = CreateCompatibleBitmap(hdcScreen, cxDstImg * cImagesX, cyDstImg * cImagesY);
hbmOldDst = (HBITMAP)SelectObject(hdcDst, hbmNew);
ReleaseDC(NULL, hdcScreen);
// BLAST!
for (j = 0, yDest = 0, yBmp = 0; j < cImagesY; j++, yDest += cyDstImg, yBmp += cySrcImg)
{
for (i = 0, xDest = 0, xBmp = 0; i < cImagesX; i++, xDest += cxDstImg, xBmp += cxSrcImg)
{
StretchBlt(hdcDst, xDest, yDest, cxDstImg, cyDstImg,
hdcSrc, xBmp, yBmp, cxSrcImg, cySrcImg,
SRCCOPY);
}
}
// Free allocated memory
SelectObject(hdcSrc, hbmOldSrc);
SelectObject(hdcDst, hbmOldDst);
DeleteDC(hdcSrc);
DeleteDC(hdcDst);
// Delete the passed in bitmap
DeleteObject(*phbm);
*phbm = hbmNew;
fRet = TRUE;
donestretch:
return fRet;
}
static BOOL HIDPI_StretchIcon_Internal(
HICON hiconIn,
HICON* phiconOut,
int cxIcon,
int cyIcon
)
{
ICONINFO iconinfo;
HDC hdc;
HBITMAP hbmImage, hbmMask;
HBITMAP hbmOld;
BOOL fDrawMaskOK;
BOOL fDrawImageOK;
*phiconOut = NULL;
hdc = CreateCompatibleDC(NULL);
hbmMask = CreateCompatibleBitmap(hdc, cxIcon, cyIcon);
hbmOld = (HBITMAP)SelectObject(hdc, hbmMask);
fDrawMaskOK = DrawIconEx(hdc, 0, 0, hiconIn, cxIcon, cyIcon, 0, NULL, DI_MASK);
SelectObject(hdc, hbmOld);
hbmImage = CreateBitmap(cxIcon, cyIcon, 1, GetDeviceCaps(hdc, BITSPIXEL), NULL);
hbmOld = (HBITMAP)SelectObject(hdc, hbmImage);
fDrawImageOK = DrawIconEx(hdc, 0, 0, hiconIn, cxIcon, cyIcon, 0, NULL, DI_IMAGE);
SelectObject(hdc, hbmOld);
if (fDrawImageOK && fDrawMaskOK)
{
iconinfo.fIcon = TRUE;
iconinfo.hbmColor = hbmImage;
iconinfo.hbmMask = hbmMask;
*phiconOut = CreateIconIndirect(&iconinfo);
}
DeleteObject(hbmImage);
DeleteObject(hbmMask);
DeleteDC(hdc);
return (fDrawImageOK && fDrawMaskOK && *phiconOut != NULL) ? TRUE : FALSE;
}
BOOL HIDPI_StretchIcon(
HICON* phic,
int cxIcon,
int cyIcon
)
{
HICON hiconOut;
if (HIDPI_StretchIcon_Internal(*phic, &hiconOut, cxIcon, cyIcon))
{
DestroyIcon(*phic);
*phic = hiconOut;
return TRUE;
}
return FALSE;
}
BOOL HIDPI_GetBitmapLogPixels(
HINSTANCE hinst,
LPCTSTR lpbmp,
int* pnLogPixelsX,
int* pnLogPixelsY
)
{
BOOL fRet = FALSE;
HRSRC hResource;
HGLOBAL hResourceBitmap = NULL;
BITMAPINFO* pBitmapInfo;
int PelsPerMeterX, PelsPerMeterY;
*pnLogPixelsX = 0;
*pnLogPixelsY = 0;
hResource = FindResource(hinst, lpbmp, RT_BITMAP);
if (!hResource)
{
goto error;
}
hResourceBitmap = LoadResource(hinst, hResource);
if (!hResourceBitmap)
{
goto error;
}
pBitmapInfo = (BITMAPINFO*)LockResource(hResourceBitmap);
if (!pBitmapInfo)
{
goto error;
}
// There are at least three kind value of PslsPerMeter used for 96 DPI bitmap:
// 0 - the bitmap just simply doesn't set this value
// 2834 - 72 DPI
// 3780 - 96 DPI
// So any value of PslsPerMeter under 3780 should be treated as 96 DPI bitmap.
PelsPerMeterX = (pBitmapInfo->bmiHeader.biXPelsPerMeter < 3780) ? 3780 : pBitmapInfo->bmiHeader.biXPelsPerMeter;
PelsPerMeterY = (pBitmapInfo->bmiHeader.biYPelsPerMeter < 3780) ? 3780 : pBitmapInfo->bmiHeader.biYPelsPerMeter;
// The formula for converting PelsPerMeter to LogPixels(DPI) is:
// LogPixels = PelsPerMeter / 39.37
// ( PelsPerMeter : Pixels per meter )
// ( LogPixels : Pixels per inch )
// Note: We need to round up.
*pnLogPixelsX = (int)((PelsPerMeterX * 100 + 1968) / 3937);
*pnLogPixelsY = (int)((PelsPerMeterY * 100 + 1968) / 3937);
fRet = TRUE;
error:
return fRet;
}
HIMAGELIST HIDPI_ImageList_LoadImage(
HINSTANCE hinst,
LPCTSTR lpbmp,
int cx,
int cGrow,
COLORREF crMask,
UINT uType,
UINT uFlags
)
{
HBITMAP hbmImage = NULL;
HIMAGELIST piml = NULL;
BITMAP bm;
int cImages, cxImage, cy;
int BmpLogPixelsX, BmpLogPixelsY;
UINT flags;
if ((uType != IMAGE_BITMAP) || // Image type is not IMAGE_BITMAP
(cx == 0)) // Caller doesn't care about the dimensions of the image - assumes the ones in the file
{
piml = ImageList_LoadImage(hinst, lpbmp, cx, cGrow, crMask, uType, uFlags);
goto cleanup;
}
if (!HIDPI_GetBitmapLogPixels(hinst, lpbmp, &BmpLogPixelsX, &BmpLogPixelsY))
{
goto cleanup;
}
hbmImage = (HBITMAP)LoadImage(hinst, lpbmp, uType, 0, 0, uFlags);
if (!hbmImage || (sizeof(bm) != GetObject(hbmImage, sizeof(bm), &bm)))
{
goto cleanup;
}
// do we need to scale this image?
if (BmpLogPixelsX == g_HIDPI_LogPixelsX)
{
piml = ImageList_LoadImage(hinst, lpbmp, cx, cGrow, crMask, uType, uFlags);
goto cleanup;
}
cxImage = HIDPIMulDiv(cx, BmpLogPixelsX, g_HIDPI_LogPixelsX);
// Bitmap width should be multiple integral of image width.
// If not, that means either your bitmap is wrong or passed in cx is wrong.
// ASSERT((bm.bmWidth % cxImage) == 0);
cImages = bm.bmWidth / cxImage;
cy = HIDPIMulDiv(bm.bmHeight, g_HIDPI_LogPixelsY, BmpLogPixelsY);
if ((g_HIDPI_LogPixelsX % BmpLogPixelsX) == 0)
{
HIDPI_StretchBitmap(&hbmImage, cx * cImages, cy, 1, 1);
}
else
{
// Here means the DPI is not integral multiple of standard DPI (96DPI).
// So if we stretch entire bitmap together, we are not sure each indivisual
// image will be stretch to right place. It is controled by StretchBlt().
// (for example, a 16 pixel icon, the first one might be stretch to 22 pixels
// and next one might be stretched to 20 pixels)
// What we have to do here is stretching indivisual image separately to make sure
// every one is stretched properly.
HIDPI_StretchBitmap(&hbmImage, cx, cy, cImages, 1);
}
flags = 0;
// ILC_MASK is important for supporting CLR_DEFAULT
if (crMask != CLR_NONE)
{
flags |= ILC_MASK;
}
// ILC_COLORMASK bits are important if we ever want to Merge ImageLists
if (bm.bmBits)
{
flags |= (bm.bmBitsPixel & ILC_COLORMASK);
}
// bitmap MUST be de-selected from the DC
// create the image list of the size asked for.
piml = ImageList_Create(cx, cy, flags, cImages, cGrow);
if (piml)
{
int added;
if (crMask == CLR_NONE)
{
added = ImageList_Add(piml, hbmImage, NULL);
}
else
{
added = ImageList_AddMasked(piml, hbmImage, crMask);
}
if (added < 0)
{
ImageList_Destroy(piml);
piml = NULL;
}
}
cleanup:
DeleteObject(hbmImage);
return piml;
}
int HIDPI_ImageList_ReplaceIcon(HIMAGELIST himl, int i, HICON hicon)
{
int iRet;
int cxIcon, cyIcon;
HICON hiconStretched;
ImageList_GetIconSize(himl, &cxIcon, &cyIcon);
HIDPI_StretchIcon_Internal(hicon, &hiconStretched, cxIcon, cyIcon);
if (hiconStretched != NULL)
{
iRet = ImageList_ReplaceIcon(himl, i, hiconStretched);
DestroyIcon(hiconStretched);
}
else
{
iRet = ImageList_ReplaceIcon(himl, i, hicon);
}
return iRet;
}
BOOL HIDPI_RectangleInternal(HDC hdc, int nLeft, int nTop, int nRight, int nBottom, int nThickness)
{
int nOff = nThickness/2;
nLeft += nOff;
nTop += nOff;
nRight -= nOff;
nBottom -= nOff;
return Rectangle(hdc, nLeft, nTop, nRight, nBottom);
}
#define BORDERX_PEN 32
BOOL HIDPI_BorderRectangle(HDC hdc, int nLeft, int nTop, int nRight, int nBottom)
{
HPEN hpenOld;
BOOL bRet;
hpenOld = (HPEN)SelectObject(hdc, (HPEN) GetStockObject(BORDERX_PEN));
bRet = HIDPI_RectangleInternal(hdc, nLeft, nTop, nRight, nBottom, GetSystemMetrics(SM_CXBORDER));
SelectObject(hdc, hpenOld);
return bRet;
}
BOOL HIDPI_Rectangle(HDC hdc, int nLeft, int nTop, int nRight, int nBottom)
{
LOGPEN lpenSel;
HPEN hpenSel;
// Obtain current pen thickness
hpenSel = (HPEN)GetCurrentObject(hdc, OBJ_PEN);
GetObject(hpenSel, sizeof(lpenSel), &lpenSel);
return HIDPI_RectangleInternal(hdc, nLeft, nTop, nRight, nBottom, lpenSel.lopnWidth.x);
}
BOOL HIDPI_PolylineInternal(HDC hdc, const POINT *lppt, int cPoints, int nStyle, int nThickness)
{
int i;
int nHOff = 0, nVOff = 0;
BOOL bRet = TRUE;
POINT pts[2];
if (! (nStyle & PS_BIAS_MASK))
{
// No drawing bias. Draw normally
return Polyline(hdc, lppt, cPoints);
}
// Make sure caller didn't try to get both a left and a right bias or both a down and an up bias
// ASSERT(!(nStyle & PS_LEFTBIAS) || !(nStyle & PS_RIGHTBIAS));
// ASSERT(!(nStyle & PS_UPBIAS) || !(nStyle & PS_DOWNBIAS));
if (nStyle & PS_LEFTBIAS)
{
nHOff = -((nThickness-1)/2);
}
if (nStyle & PS_RIGHTBIAS)
{
nHOff = nThickness/2;
}
if (nStyle & PS_UPBIAS)
{
nVOff = -((nThickness-1)/2);
}
if (nStyle & PS_DOWNBIAS)
{
nVOff = nThickness/2;
}
for (i = 1; i < cPoints; i++)
{
// Use the two points that specify current line segment
memcpy(pts, &lppt[i-1], 2*sizeof(POINT));
if (abs(lppt[i].x - lppt[i-1].x) <= abs(lppt[i].y - lppt[i-1].y))
{
// Shift current line segment horizontally if abs(slope) >= 1
pts[0].x += nHOff;
pts[1].x += nHOff;
}
else
{
// Shift current line segment vertically if abs(slope) < 1
pts[0].y += nVOff;
pts[1].y += nVOff;
}
bRet = bRet && Polyline(hdc, pts, 2);
if (!bRet)
{
goto Error;
}
}
Error:
return bRet;
}
BOOL HIDPI_BorderPolyline(HDC hdc, const POINT *lppt, int cPoints, int nStyle)
{
HPEN hpenOld;
BOOL bRet;
hpenOld = (HPEN)SelectObject(hdc, (HPEN) GetStockObject(BORDERX_PEN));
bRet = HIDPI_PolylineInternal(hdc, lppt, cPoints, nStyle, GetSystemMetrics(SM_CXBORDER));
SelectObject(hdc, hpenOld);
return bRet;
}
BOOL HIDPI_Polyline(HDC hdc, const POINT *lppt, int cPoints, int nStyle)
{
LOGPEN lpenSel;
HPEN hpenSel;
// Obtain current pen thickness
hpenSel = (HPEN)GetCurrentObject(hdc, OBJ_PEN);
GetObject(hpenSel, sizeof(lpenSel), &lpenSel);
return HIDPI_PolylineInternal(hdc, lppt, cPoints, nStyle, lpenSel.lopnWidth.x);
}
//
// Called by RelayoutDialog to advance to the next item in the dialog template.
//
static LPBYTE WalkDialogData(LPBYTE lpData)
{
LPWORD lpWord = (LPWORD)lpData;
if (*lpWord == 0xFFFF)
{
return (LPBYTE)(lpWord + 2);
}
while (*lpWord != 0x0000)
{
lpWord++;
}
return (LPBYTE)(lpWord + 1);
}
//
// Post-processing step for each dialog item.
// Static controls and buttons: change text and bitmaps.
// Listboxes and combo boxes: ensures that the selected item is visible.
//
static void FixupDialogItem(
HINSTANCE hInst,
HWND hDlg,
LPDLGITEMTEMPLATE lpDlgItem,
LPWORD lpClass,
LPWORD lpData)
{
if (lpClass[0] == 0xFFFF)
{
switch (lpClass[1])
{
case 0x0080: // button
case 0x0082: // static
{
if (lpData[0] == 0xFFFF)
{
if (lpDlgItem->style & SS_ICON)
{
HICON hOld = (HICON)SendDlgItemMessageW(hDlg, lpDlgItem->id, STM_GETIMAGE, IMAGE_ICON, 0);
HICON hNew = LoadIcon(hInst, MAKEINTRESOURCE(lpData[1]));
SendDlgItemMessageW(hDlg, lpDlgItem->id, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hNew);
DestroyIcon(hOld);
}
else if (lpDlgItem->style & SS_BITMAP)
{
HBITMAP hOld = (HBITMAP)SendDlgItemMessageW(hDlg, lpDlgItem->id, STM_GETIMAGE, IMAGE_BITMAP, 0);
HBITMAP hNew = LoadBitmap(hInst, MAKEINTRESOURCE(lpData[1]));
SendDlgItemMessageW(hDlg, lpDlgItem->id, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hNew);
DeleteObject(hOld);
}
}
else // lpData[0] is not 0xFFFF (it's text).
{
SetDlgItemTextW(hDlg, lpDlgItem->id, (LPCTSTR)lpData);
}
}
break;
case 0x0083: // list box
{
INT nSel = SendDlgItemMessageW(hDlg, lpDlgItem->id, LB_GETCURSEL, 0, 0);
if (nSel != LB_ERR)
{
SendDlgItemMessageW(hDlg, lpDlgItem->id, LB_SETCURSEL, nSel, 0);
}
}
break;
case 0x0085: // combo box
{
INT nSel = SendDlgItemMessageW(hDlg, lpDlgItem->id, CB_GETCURSEL, 0, 0);
if (nSel != CB_ERR)
{
SendDlgItemMessageW(hDlg, lpDlgItem->id, CB_SETCURSEL, nSel, 0);
}
}
break;
}
}
}
BOOL RelayoutDialog(HINSTANCE hInst, HWND hDlg, LPCWSTR iddTemplate)
{
HRSRC hRsrc = FindResource((HMODULE)hInst, iddTemplate, RT_DIALOG);
INT nStatics = 0;
HGLOBAL hGlobal;
LPBYTE lpData;
LPDLGTEMPLATE lpTemplate;
HDWP hDWP;
int i;
LPDLGITEMTEMPLATE lpDlgItem;
HWND hwndCtl;
LPWORD lpClass;
WORD cbExtra;
if (hRsrc == NULL)
{
return FALSE;
}
hGlobal = LoadResource((HMODULE)hInst, hRsrc);
if (hGlobal == NULL)
{
return FALSE;
}
lpData = (LPBYTE)LockResource(hGlobal);
lpTemplate = (LPDLGTEMPLATE)lpData;
hDWP = BeginDeferWindowPos(lpTemplate->cdit);
//
// For more information about the data structures that we are walking,
// consult the DLGTEMPLATE and DLGITEMTEMPLATE documentation on MSDN.
//
lpData += sizeof(DLGTEMPLATE);
lpData = WalkDialogData(lpData); // menu
lpData = WalkDialogData(lpData); // class
lpData = WalkDialogData(lpData); // title
if (lpTemplate->style & DS_SETFONT)
{
lpData += sizeof(WORD); // font size.
lpData = WalkDialogData(lpData); // font face.
}
for (i = 0; i < lpTemplate->cdit; i++)
{
lpData = (LPBYTE) (((INT)lpData + 3) & ~3); // force to DWORD boundary.
lpDlgItem = (LPDLGITEMTEMPLATE)lpData;
hwndCtl = GetDlgItem(hDlg, lpDlgItem->id);
if (lpDlgItem->id == 0xFFFF)
{
nStatics++;
}
//
// Move the item around.
//
{
RECT r;
r.left = lpDlgItem->x;
r.top = lpDlgItem->y;
r.right = lpDlgItem->x + lpDlgItem->cx;
r.bottom = lpDlgItem->y + lpDlgItem->cy;
MapDialogRect(hDlg, &r);
DeferWindowPos(hDWP, hwndCtl, NULL,
r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_NOZORDER);
}
lpData += sizeof(DLGITEMTEMPLATE);
lpClass = (LPWORD)lpData;
lpData = WalkDialogData(lpData); // class
//
// Do some special handling for each dialog item (changing text,
// bitmaps, ensuring visible, etc.
//
FixupDialogItem(hInst, hDlg, lpDlgItem, lpClass, (LPWORD)lpData);
lpData = WalkDialogData(lpData); // title
cbExtra = *((LPWORD)lpData); // extra class data.
lpData += (cbExtra ? cbExtra : sizeof(WORD));
}
EndDeferWindowPos(hDWP);
return nStatics < 2 ? TRUE : FALSE;
}