You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2374 lines
62 KiB
2374 lines
62 KiB
|
|
/*****************************************************************************
|
|
|
|
C L I P B O O K D I S P L A Y
|
|
|
|
Name: clipdsp.c
|
|
Date: 21-Jan-1994
|
|
Creator: Unknown
|
|
|
|
Description:
|
|
This module handles the drawing of the clipbook displays.
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
#define WIN31
|
|
#include <windows.h>
|
|
#include <strsafe.h>
|
|
#include "common.h"
|
|
#include "clipbook.h"
|
|
#include "clpbkrc.h"
|
|
#include "clipbrd.h"
|
|
#include "clipdsp.h"
|
|
#include "debugout.h"
|
|
#include "cvutil.h"
|
|
|
|
|
|
#define ifmtMax (sizeof(rgfmt)/sizeof(WORD))
|
|
|
|
|
|
static MFENUMPROC lpEnumMetaProc;
|
|
|
|
|
|
BOOL fOwnerDisplay;
|
|
HBRUSH hbrBackground;
|
|
HMENU hDispMenu;
|
|
|
|
|
|
|
|
/* The scroll information for OWNER display is to be preserved, whenever
|
|
* the display changes between OWNER and NON-OWNER; The following globals
|
|
* are used to save and restore the scroll info.
|
|
*/
|
|
|
|
// winball: since only the Clipboard window supports owner display,
|
|
// this info is not replicated for each MDI child...
|
|
|
|
int OwnVerMin;
|
|
int OwnVerMax;
|
|
int OwnHorMin;
|
|
int OwnHorMax;
|
|
|
|
int OwnVerPos;
|
|
int OwnHorPos;
|
|
|
|
|
|
|
|
/* Defines priority order for show format */
|
|
WORD rgfmt[] = {
|
|
CF_OWNERDISPLAY,
|
|
|
|
CF_UNICODETEXT,
|
|
CF_TEXT,
|
|
CF_OEMTEXT,
|
|
|
|
|
|
CF_ENHMETAFILE,
|
|
CF_METAFILEPICT,
|
|
CF_DIB,
|
|
CF_BITMAP,
|
|
|
|
CF_DSPTEXT,
|
|
CF_DSPBITMAP,
|
|
CF_DSPMETAFILEPICT,
|
|
CF_DSPENHMETAFILE,
|
|
|
|
CF_PALETTE,
|
|
CF_RIFF,
|
|
CF_WAVE,
|
|
CF_PENDATA,
|
|
CF_SYLK,
|
|
CF_DIF,
|
|
CF_TIFF,
|
|
CF_LOCALE
|
|
};
|
|
|
|
|
|
void ShowString( HWND, HDC, WORD);
|
|
|
|
|
|
|
|
/*
|
|
* MyOpenClipBoard
|
|
*/
|
|
|
|
BOOL MyOpenClipboard(
|
|
HWND hWnd)
|
|
{
|
|
HDC hDC;
|
|
RECT Rect;
|
|
|
|
if( VOpenClipboard( GETMDIINFO(hWnd)->pVClpbrd, hWnd ))
|
|
return(TRUE);
|
|
|
|
|
|
PERROR(TEXT("MyOpenClipboard fail\r\n"));
|
|
|
|
|
|
/* Some app forgot to close the clipboard */
|
|
hDC = GetDC(hWnd);
|
|
|
|
GetClientRect(hWnd, (LPRECT)&Rect);
|
|
FillRect(hDC, (LPRECT)&Rect, hbrBackground);
|
|
ShowString( hWnd, hDC, IDS_ALREADYOPEN);
|
|
|
|
ReleaseDC(hWnd, hDC);
|
|
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* SetCharDimensions
|
|
*/
|
|
|
|
void SetCharDimensions(
|
|
HWND hWnd,
|
|
HFONT hFont)
|
|
|
|
{
|
|
register HDC hdc;
|
|
TEXTMETRIC tm;
|
|
PMDIINFO pMDI;
|
|
|
|
|
|
pMDI = GETMDIINFO(hWnd);
|
|
|
|
if (pMDI)
|
|
{
|
|
hdc = GetDC(hWnd);
|
|
SelectObject(hdc, hFont);
|
|
GetTextMetrics(hdc, (LPTEXTMETRIC)&tm);
|
|
ReleaseDC(hWnd, hdc);
|
|
|
|
pMDI->cxChar = (WORD)tm.tmAveCharWidth;
|
|
pMDI->cxMaxCharWidth = (WORD)tm.tmMaxCharWidth;
|
|
pMDI->cyLine = (WORD)(tm.tmHeight + tm.tmExternalLeading);
|
|
pMDI->cxMargin = pMDI->cxChar / 2;
|
|
pMDI->cyMargin = pMDI->cyLine / 4;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* ChangeCharDimensions
|
|
*/
|
|
|
|
void ChangeCharDimensions(
|
|
HWND hwnd,
|
|
UINT wOldFormat,
|
|
UINT wNewFormat)
|
|
{
|
|
/* Check if the font has changed. */
|
|
if (wOldFormat == CF_OEMTEXT)
|
|
{
|
|
if (wNewFormat != CF_OEMTEXT) // Select default system font sizes
|
|
SetCharDimensions(hwnd, GetStockObject ( SYSTEM_FONT ) );
|
|
}
|
|
else if (wNewFormat == CF_OEMTEXT) // Select OEM font sizes
|
|
SetCharDimensions(hwnd, GetStockObject ( OEM_FIXED_FONT ) );
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* ClipbrdVScroll
|
|
*
|
|
* Scroll contents of window vertically, according to action code in wParam.
|
|
*/
|
|
|
|
void ClipbrdVScroll (
|
|
HWND hwnd,
|
|
WORD wParam,
|
|
WORD wThumb)
|
|
{
|
|
int cyWindow;
|
|
long dyScroll;
|
|
long cyScrollT;
|
|
long dyScrollAbs;
|
|
long cyPartialChar;
|
|
PMDIINFO pMDI;
|
|
|
|
|
|
|
|
pMDI = GETMDIINFO(hwnd);
|
|
|
|
if (pMDI)
|
|
{
|
|
|
|
/* Ensure that all the bits are valid first, before scrolling them */
|
|
UpdateWindow(hwnd);
|
|
|
|
cyScrollT = pMDI->cyScrollNow;
|
|
cyWindow = pMDI->rcWindow.bottom - pMDI->rcWindow.top;
|
|
|
|
/* Compute scroll results as an effect on cyScrollNow */
|
|
switch (wParam)
|
|
{
|
|
case SB_LINEUP:
|
|
cyScrollT -= pMDI->cyLine;
|
|
break;
|
|
|
|
case SB_LINEDOWN:
|
|
cyScrollT += pMDI->cyLine;
|
|
break;
|
|
|
|
case SB_THUMBPOSITION:
|
|
cyScrollT = (LONG)(((LONG)wThumb * pMDI->cyScrollLast) / VPOSLAST);
|
|
break;
|
|
|
|
case SB_PAGEUP:
|
|
case SB_PAGEDOWN:
|
|
{
|
|
int cyPageScroll;
|
|
|
|
cyPageScroll = cyWindow - pMDI->cyLine;
|
|
|
|
if (cyPageScroll < (int)(pMDI->cyLine))
|
|
cyPageScroll = pMDI->cyLine;
|
|
|
|
cyScrollT += (wParam == SB_PAGEUP) ? -cyPageScroll : cyPageScroll;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
if ((cyScrollT < 0) || (pMDI->cyScrollLast <= 0))
|
|
cyScrollT = 0;
|
|
else if (cyScrollT > pMDI->cyScrollLast)
|
|
cyScrollT = pMDI->cyScrollLast;
|
|
else if (cyPartialChar = cyScrollT % pMDI->cyLine)
|
|
{
|
|
/* Round to the nearest character increment. */
|
|
if (cyPartialChar > ((int)(pMDI->cyLine) >> 1))
|
|
cyScrollT += pMDI->cyLine;
|
|
cyScrollT -= cyPartialChar;
|
|
}
|
|
|
|
|
|
|
|
dyScroll = pMDI->cyScrollNow - cyScrollT;
|
|
|
|
if (dyScroll > 0)
|
|
dyScrollAbs = dyScroll;
|
|
else if (dyScroll < 0)
|
|
dyScrollAbs = -dyScroll;
|
|
else
|
|
return; /* Scrolling has no effect here. */
|
|
|
|
pMDI->cyScrollNow = cyScrollT;
|
|
|
|
if (dyScrollAbs >= pMDI->rcWindow.bottom - pMDI->rcWindow.top)
|
|
/* ScrollWindow does not handle this case */
|
|
InvalidateRect(hwnd, (LPRECT)&(pMDI->rcWindow), TRUE);
|
|
else
|
|
ScrollWindow(hwnd, 0,(int)dyScroll, &(pMDI->rcWindow), &(pMDI->rcWindow));
|
|
|
|
UpdateWindow(hwnd);
|
|
|
|
SetScrollPos (pMDI->hwndVscroll,
|
|
SB_CTL,
|
|
(pMDI->cyScrollLast <= 0) ?
|
|
0 :
|
|
(int)((cyScrollT * (DWORD)VPOSLAST) / pMDI->cyScrollLast),
|
|
TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* ClipbrdHScroll
|
|
*
|
|
* Scroll contents of window horizontally, according to op code in wParam.
|
|
*/
|
|
|
|
void ClipbrdHScroll (
|
|
HWND hwnd,
|
|
WORD wParam,
|
|
WORD wThumb)
|
|
{
|
|
register int dxScroll;
|
|
register int cxScrollT;
|
|
int cxWindow;
|
|
int dxScrollAbs;
|
|
int cxPartialChar;
|
|
PMDIINFO pMDI;
|
|
|
|
|
|
|
|
pMDI = GETMDIINFO(hwnd);
|
|
|
|
if (pMDI)
|
|
{
|
|
|
|
cxScrollT = pMDI->cxScrollNow;
|
|
cxWindow = pMDI->rcWindow.right - pMDI->rcWindow.left;
|
|
|
|
/* Compute scroll results as an effect on cxScrollNow */
|
|
switch (wParam)
|
|
{
|
|
case SB_LINEUP:
|
|
cxScrollT -= pMDI->cxChar;
|
|
break;
|
|
|
|
case SB_LINEDOWN:
|
|
cxScrollT += pMDI->cxChar;
|
|
break;
|
|
|
|
case SB_THUMBPOSITION:
|
|
cxScrollT = (int)(((LONG)wThumb * (LONG)pMDI->cxScrollLast) / HPOSLAST);
|
|
break;
|
|
|
|
case SB_PAGEUP:
|
|
case SB_PAGEDOWN:
|
|
{
|
|
int cxPageScroll;
|
|
|
|
cxPageScroll = cxWindow - pMDI->cxChar;
|
|
if (cxPageScroll < (int)(pMDI->cxChar))
|
|
cxPageScroll = pMDI->cxChar;
|
|
|
|
cxScrollT += (wParam == SB_PAGEUP) ? -cxPageScroll : cxPageScroll;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
if ((cxScrollT < 0) || (pMDI->cxScrollLast <= 0))
|
|
cxScrollT = 0;
|
|
else if (cxScrollT > pMDI->cxScrollLast)
|
|
cxScrollT = pMDI->cxScrollLast;
|
|
else if (cxPartialChar = cxScrollT % pMDI->cxChar)
|
|
{ /* Round to the nearest character increment */
|
|
if (cxPartialChar > ((int)(pMDI->cxChar) >> 1))
|
|
cxScrollT += pMDI->cxChar;
|
|
cxScrollT -= cxPartialChar;
|
|
}
|
|
|
|
|
|
|
|
/* Now we have a good cxScrollT value */
|
|
|
|
dxScroll = pMDI->cxScrollNow - cxScrollT;
|
|
if (dxScroll > 0)
|
|
dxScrollAbs = dxScroll;
|
|
else if (dxScroll < 0)
|
|
dxScrollAbs = -dxScroll;
|
|
else
|
|
return; /* Scrolling has no effect here. */
|
|
|
|
|
|
pMDI->cxScrollNow = cxScrollT;
|
|
|
|
if (dxScrollAbs >= pMDI->rcWindow.right - pMDI->rcWindow.left)
|
|
/* ScrollWindow does not handle this case */
|
|
InvalidateRect( hwnd, (LPRECT) &(pMDI->rcWindow), TRUE );
|
|
else
|
|
ScrollWindow(hwnd, dxScroll, 0, (LPRECT)&(pMDI->rcWindow),
|
|
(LPRECT)&(pMDI->rcWindow));
|
|
|
|
UpdateWindow(hwnd);
|
|
|
|
SetScrollPos (pMDI->hwndHscroll,
|
|
SB_CTL,
|
|
(pMDI->cxScrollLast <= 0) ?
|
|
0 :
|
|
(int)(((DWORD)cxScrollT * (DWORD)HPOSLAST) / (DWORD)(pMDI->cxScrollLast)),
|
|
TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* DibPaletteSize
|
|
*/
|
|
|
|
int DibPaletteSize(
|
|
LPBITMAPINFOHEADER lpbi)
|
|
{
|
|
register int bits;
|
|
register int nRet;
|
|
|
|
/* With the new format headers, the size of the palette is in biClrUsed
|
|
* else is dependent on bits per pixel.
|
|
*/
|
|
|
|
if (lpbi->biSize != sizeof(BITMAPCOREHEADER))
|
|
{
|
|
if (lpbi->biClrUsed != 0)
|
|
{
|
|
nRet = lpbi->biClrUsed * sizeof(RGBQUAD);
|
|
}
|
|
else
|
|
{
|
|
bits = lpbi->biBitCount;
|
|
|
|
if (24 == bits)
|
|
{
|
|
nRet = 0;
|
|
}
|
|
else if (16 == bits || 32 == bits)
|
|
{
|
|
nRet = 3 * sizeof(DWORD);
|
|
}
|
|
else
|
|
{
|
|
nRet = (1 << bits) * sizeof(RGBQUAD);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bits = ((LPBITMAPCOREHEADER)lpbi)->bcBitCount;
|
|
nRet = (bits == 24) ? 0 : (1 << bits) * sizeof(RGBTRIPLE);
|
|
}
|
|
|
|
return(nRet);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* DibGetInfo
|
|
*/
|
|
|
|
void DibGetInfo(
|
|
HANDLE hdib,
|
|
LPBITMAP pbm)
|
|
|
|
{
|
|
LPBITMAPINFOHEADER lpbi;
|
|
|
|
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hdib);
|
|
|
|
if (lpbi->biSize != sizeof(BITMAPCOREHEADER))
|
|
{
|
|
pbm->bmWidth = (int)lpbi->biWidth;
|
|
pbm->bmHeight = (int)lpbi->biHeight;
|
|
}
|
|
else
|
|
{
|
|
pbm->bmWidth = (int)((LPBITMAPCOREHEADER)lpbi)->bcWidth;
|
|
pbm->bmHeight = (int)((LPBITMAPCOREHEADER)lpbi)->bcHeight;
|
|
}
|
|
|
|
GlobalUnlock(hdib);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* DrawDib
|
|
*/
|
|
|
|
BOOL DrawDib(
|
|
HWND hwnd,
|
|
HDC hdc,
|
|
int x0,
|
|
int y0,
|
|
HANDLE hdib)
|
|
{
|
|
LPBITMAPINFOHEADER lpbi;
|
|
BITMAP bm;
|
|
LPSTR lpBits;
|
|
BOOL fOK = FALSE;
|
|
|
|
if (hdib)
|
|
{
|
|
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hdib);
|
|
|
|
if (lpbi)
|
|
{
|
|
DibGetInfo(hdib, (LPBITMAP)&bm);
|
|
|
|
lpBits = (LPSTR)lpbi + (WORD)lpbi->biSize + DibPaletteSize(lpbi);
|
|
|
|
SetDIBitsToDevice (hdc,
|
|
x0,
|
|
y0,
|
|
bm.bmWidth,
|
|
bm.bmHeight,
|
|
0,
|
|
0,
|
|
0,
|
|
bm.bmHeight,
|
|
lpBits,
|
|
(LPBITMAPINFO)lpbi,
|
|
DIB_RGB_COLORS);
|
|
|
|
GlobalUnlock(hdib);
|
|
fOK = TRUE;
|
|
}
|
|
}
|
|
|
|
return(fOK);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* FShowDIBitmap
|
|
*/
|
|
|
|
BOOL FShowDIBitmap (
|
|
HWND hwnd,
|
|
register HDC hdc,
|
|
PRECT prc,
|
|
HANDLE hdib, //Bitmap in DIB format
|
|
int cxScroll,
|
|
int cyScroll)
|
|
{
|
|
BITMAP bm;
|
|
PMDIINFO pMDI;
|
|
|
|
pMDI = GETMDIINFO(hwnd);
|
|
|
|
if (pMDI)
|
|
{
|
|
DibGetInfo(hdib, (LPBITMAP)&bm);
|
|
|
|
|
|
// If window's been resized, determine maximum scroll positions.
|
|
if (pMDI->cyScrollLast == -1)
|
|
{
|
|
/* Compute last scroll offset into bitmap */
|
|
pMDI->cyScrollLast = bm.bmHeight -
|
|
(pMDI->rcWindow.bottom - pMDI->rcWindow.top);
|
|
if (pMDI->cyScrollLast < 0)
|
|
{
|
|
pMDI->cyScrollLast = 0;
|
|
}
|
|
}
|
|
|
|
if (pMDI->cxScrollLast == -1)
|
|
{
|
|
/* Compute last scroll offset into bitmap */
|
|
pMDI->cxScrollLast = bm.bmWidth -
|
|
(pMDI->rcWindow.right - pMDI->rcWindow.left);
|
|
if (pMDI->cxScrollLast < 0)
|
|
{
|
|
pMDI->cxScrollLast = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
SaveDC(hdc);
|
|
IntersectClipRect (hdc, prc->left, prc->top, prc->right, prc->bottom);
|
|
SetViewportOrgEx (hdc,prc->left - cxScroll, prc->top - cyScroll,NULL);
|
|
DrawDib (hwnd, hdc, 0, 0, hdib);
|
|
RestoreDC(hdc, -1);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* FShowBitmap
|
|
*/
|
|
|
|
BOOL FShowBitmap (
|
|
HWND hwnd,
|
|
HDC hdc,
|
|
register PRECT prc,
|
|
HBITMAP hbm,
|
|
int cxScroll,
|
|
int cyScroll)
|
|
{
|
|
register HDC hMemDC;
|
|
BITMAP bitmap;
|
|
int cxBlt, cyBlt;
|
|
int cxRect, cyRect;
|
|
PMDIINFO pMDI;
|
|
|
|
pMDI = GETMDIINFO(hwnd);
|
|
|
|
if ((hMemDC = CreateCompatibleDC(hdc)) == NULL)
|
|
return(FALSE);
|
|
|
|
if (!SelectObject(hMemDC, (HBITMAP)hbm))
|
|
{
|
|
DeleteDC(hMemDC);
|
|
ShowString( hwnd, hdc, IDS_BADBMPFMT );
|
|
return TRUE;
|
|
}
|
|
|
|
GetObject((HBITMAP)hbm, sizeof(BITMAP), (LPSTR)&bitmap);
|
|
|
|
|
|
if (pMDI->cyScrollLast == -1)
|
|
{
|
|
/* Compute last scroll offset into bitmap */
|
|
pMDI->cyScrollLast = bitmap.bmHeight - (pMDI->rcWindow.bottom - pMDI->rcWindow.top);
|
|
if (pMDI->cyScrollLast < 0)
|
|
pMDI->cyScrollLast = 0;
|
|
}
|
|
|
|
if ( pMDI->cxScrollLast == -1)
|
|
{
|
|
/* Compute last scroll offset into bitmap */
|
|
pMDI->cxScrollLast = bitmap.bmWidth - (pMDI->rcWindow.right - pMDI->rcWindow.left);
|
|
if ( pMDI->cxScrollLast < 0)
|
|
pMDI->cxScrollLast = 0;
|
|
}
|
|
|
|
|
|
cxRect = prc->right - prc->left;
|
|
cyRect = prc->bottom - prc->top;
|
|
cxBlt = min(cxRect, bitmap.bmWidth - cxScroll);
|
|
cyBlt = min(cyRect, bitmap.bmHeight - cyScroll);
|
|
|
|
BitBlt (hdc,
|
|
prc->left,
|
|
prc->top,
|
|
cxBlt,
|
|
cyBlt,
|
|
hMemDC,
|
|
cxScroll,
|
|
cyScroll, /* X,Y offset into source DC */
|
|
SRCCOPY);
|
|
|
|
DeleteDC(hMemDC);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
#define DXPAL (pMDI->cyLine)
|
|
#define DYPAL (pMDI->cyLine)
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FShowPalette()
|
|
//
|
|
// Parameters:
|
|
// hwnd - The wMDI child we're drawing in.
|
|
// hdc - DC for the window.
|
|
// prc - Rectangle to draw.
|
|
// hpal - The palette to display.
|
|
// cxScroll, cyScroll - Scroll position in pels OF PRC. NOT OF THE WINDOW.
|
|
// Derive window scroll position by doing a cxScroll -= pMDI->cxScrollNow
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL FShowPalette(
|
|
HWND hwnd,
|
|
register HDC hdc,
|
|
register PRECT prc,
|
|
HPALETTE hpal,
|
|
int cxScroll,
|
|
int cyScroll)
|
|
{
|
|
int n;
|
|
int x, y;
|
|
int nx, ny;
|
|
int nNumEntries;
|
|
RECT rc;
|
|
HBRUSH hbr;
|
|
PMDIINFO pMDI;
|
|
BOOL fOK = FALSE;
|
|
TCHAR achHex[] = TEXT("0123456789ABCDEF");
|
|
int nFirstLineDrawn;
|
|
|
|
|
|
|
|
PINFO(TEXT("Palette: (%d,%d-%d,%d),cx %d, cy %d\r\n"),
|
|
prc->left, prc->top, prc->right, prc->bottom, cxScroll, cyScroll);
|
|
|
|
|
|
pMDI = GETMDIINFO(hwnd);
|
|
|
|
if (hpal)
|
|
{
|
|
// Correct cyScroll to show window's scroll position, not prc's.
|
|
cyScroll -= prc->top - pMDI->rcWindow.top;
|
|
PINFO(TEXT("Corrected cyScroll %d\r\n"), cyScroll);
|
|
|
|
// GetObject does not return an int-- it returns a USHORT. Thus,
|
|
// we zero out nNumEntries before getobjecting the palette.
|
|
nNumEntries = 0;
|
|
GetObject(hpal, sizeof(int), (LPSTR)&nNumEntries);
|
|
|
|
// Figure how many boxes across and tall the array of color boxes
|
|
// is
|
|
nx = ((pMDI->rcWindow.right - pMDI->rcWindow.left) / DXPAL);
|
|
if (nx == 0)
|
|
{
|
|
nx = 1;
|
|
}
|
|
ny = (nNumEntries + nx - 1) / nx;
|
|
PINFO(TEXT("%d entries, %d by %d array\r\n"), nNumEntries, nx, ny);
|
|
|
|
// If the window's been resized, we have to tell it how far you
|
|
// can scroll off to the right and down.
|
|
if ( pMDI->cyScrollLast == -1)
|
|
{
|
|
pMDI->cyScrollLast = ny * DYPAL - // Height of palette minus
|
|
pMDI->rcWindow.bottom - pMDI->rcWindow.top + // height of window plus
|
|
DYPAL; // one palette entry height.
|
|
|
|
if ( pMDI->cyScrollLast < 0)
|
|
{
|
|
pMDI->cyScrollLast = 0;
|
|
}
|
|
PINFO(TEXT("Last allowed scroll: %d\r\n"), pMDI->cyScrollLast);
|
|
}
|
|
if ( pMDI->cxScrollLast == -1)
|
|
{
|
|
/* Can't scroll palettes horizontally. */
|
|
pMDI->cxScrollLast = 0;
|
|
}
|
|
|
|
SaveDC(hdc);
|
|
IntersectClipRect(hdc, prc->left, prc->top, prc->right, prc->bottom);
|
|
SetWindowOrgEx(hdc, -pMDI->rcWindow.left, -pMDI->rcWindow.top, NULL);
|
|
|
|
// Set up the x and y positions of the first palette entry to draw
|
|
// and figure out which palette entry IS the first that needs drawing.
|
|
x = 0;
|
|
nFirstLineDrawn = (cyScroll + prc->top - pMDI->rcWindow.top)/ DYPAL;
|
|
n = nx * nFirstLineDrawn;
|
|
y = DYPAL * nFirstLineDrawn - cyScroll;
|
|
PINFO(TEXT("First entry %d at %d, %d\r\n"), n, x, y);
|
|
|
|
// While n < number of entries and the current entry isn't off the bottom
|
|
// of the window
|
|
while (n < nNumEntries && y < prc->bottom)
|
|
{
|
|
// Figure out a DXPAL by DYPAL rect going down/right from x,y
|
|
rc.left = x;
|
|
rc.top = y;
|
|
rc.right = rc.left + DXPAL;
|
|
rc.bottom = rc.top + DYPAL;
|
|
// PINFO(TEXT("(%d,%d) "), rc.left, rc.top);
|
|
|
|
// Draw a black box with the appropriate color inside.
|
|
if (RectVisible(hdc, &rc))
|
|
{
|
|
// PINFO(TEXT("<"));
|
|
|
|
// If you change this one to zero, you get a text display of
|
|
// the palette indices-- I used it to debug the draw code, 'cause
|
|
// it's near impossible, when you've got little colored
|
|
// squares, to figure out just which color is on the bottom of THAT
|
|
// square THERE, the one that was scrolled halfway off the bottom
|
|
// of the window, and you just scrolled it on. ("Well, it's sorta
|
|
// purple... of course, this entire palette is sorta purple..")
|
|
#if 1
|
|
InflateRect(&rc, -1, -1);
|
|
FrameRect(hdc, &rc, GetStockObject(BLACK_BRUSH));
|
|
InflateRect(&rc, -1, -1);
|
|
hbr = CreateSolidBrush(PALETTEINDEX(n));
|
|
FillRect(hdc, &rc, hbr);
|
|
DeleteObject(hbr);
|
|
#else
|
|
SetBkMode(hdc, TRANSPARENT);
|
|
TextOut(hdc, rc.left + 2, rc.top + 2, &achHex[(n / 16)&0x0f], 1);
|
|
TextOut(hdc, (rc.left + rc.right) / 2, rc.top + 2,
|
|
&achHex[n & 0x0f], 1);
|
|
#endif
|
|
}
|
|
|
|
// Go to next entry and advance x to the next position, "word
|
|
// wrapping" to next line if we need to
|
|
n++;
|
|
x += DXPAL;
|
|
if (0 == n % nx)
|
|
{
|
|
x = 0;
|
|
y += DYPAL;
|
|
PINFO(TEXT("Wrap at %d\r\n"), n);
|
|
}
|
|
}
|
|
RestoreDC(hdc, -1);
|
|
fOK = TRUE;
|
|
}
|
|
else
|
|
{
|
|
PERROR(TEXT("Bad palette!\r\n"));
|
|
}
|
|
return(fOK);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* PxlConvert
|
|
*
|
|
* Return the # of pixels spanned by 'val', a measurement in coordinates
|
|
* appropriate to mapping mode mm. 'pxlDeviceRes' gives the resolution
|
|
* of the device in pixels, along the axis of 'val'. 'milDeviceRes' gives
|
|
* the same resolution measurement, but in millimeters.
|
|
*/
|
|
|
|
int PxlConvert(
|
|
int mm,
|
|
int val,
|
|
int pxlDeviceRes,
|
|
int milDeviceRes)
|
|
{
|
|
register WORD wMult = 1;
|
|
register WORD wDiv = 1;
|
|
DWORD ulPxl;
|
|
DWORD ulDenom;
|
|
DWORD ulMaxInt = 0x7FFF;
|
|
|
|
if (milDeviceRes == 0)
|
|
{
|
|
/* to make sure we don't get divide-by-0 */
|
|
return(0);
|
|
}
|
|
|
|
switch (mm)
|
|
{
|
|
case MM_LOMETRIC:
|
|
wDiv = 10;
|
|
break;
|
|
|
|
case MM_HIMETRIC:
|
|
wDiv = 100;
|
|
break;
|
|
|
|
case MM_TWIPS:
|
|
wMult = 254;
|
|
wDiv = 14400;
|
|
break;
|
|
|
|
case MM_LOENGLISH:
|
|
wMult = 2540;
|
|
wDiv = 10000;
|
|
break;
|
|
|
|
case MM_HIENGLISH:
|
|
wMult = 254;
|
|
wDiv = 10000;
|
|
break;
|
|
|
|
case MM_TEXT:
|
|
return(val);
|
|
|
|
case MM_ISOTROPIC:
|
|
case MM_ANISOTROPIC:
|
|
/* These picture types have no original size */
|
|
default:
|
|
return(0);
|
|
}
|
|
|
|
/* Add denominator - 1 to numerator, to avoid roundoff */
|
|
|
|
ulDenom = (DWORD)wDiv * (DWORD)milDeviceRes;
|
|
ulPxl = (((DWORD)((DWORD)wMult * (DWORD)val * (DWORD)pxlDeviceRes)) + ulDenom - 1) / ulDenom;
|
|
|
|
return((ulPxl > ulMaxInt) ? 0 : (int)ulPxl);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* FShowEnhMetaFile
|
|
*
|
|
* Display an enhanced metafile in the specified rectangle.
|
|
*/
|
|
|
|
BOOL FShowEnhMetaFile(
|
|
HWND hwnd,
|
|
register HDC hdc,
|
|
register PRECT prc,
|
|
HANDLE hemf,
|
|
int cxScroll,
|
|
int cyScroll)
|
|
{
|
|
int cxBitmap;
|
|
int cyBitmap;
|
|
RECT rcWindow;
|
|
int f = FALSE;
|
|
PMDIINFO pMDI;
|
|
|
|
|
|
|
|
pMDI = GETMDIINFO(hwnd);
|
|
|
|
if (pMDI)
|
|
{
|
|
|
|
/* Not scrollable. Resize these into the given rect. */
|
|
|
|
pMDI->cyScrollLast = 0;
|
|
pMDI->cxScrollLast = 0;
|
|
|
|
cxBitmap = pMDI->rcWindow.right - pMDI->rcWindow.left;
|
|
cyBitmap = pMDI->rcWindow.bottom - pMDI->rcWindow.top;
|
|
|
|
|
|
/* We make the "viewport" to be an area the same size as the
|
|
* clipboard object, and set the origin and clip region so as
|
|
* to show the area we want. Note that the viewport may well be
|
|
* bigger than the window.
|
|
*/
|
|
|
|
SetMapMode(hdc, MM_TEXT);
|
|
|
|
rcWindow.left = prc->left - cxScroll;
|
|
rcWindow.top = prc->top - cyScroll;
|
|
rcWindow.right = rcWindow.left + cxBitmap;
|
|
rcWindow.bottom = rcWindow.top + cyBitmap;
|
|
|
|
f = PlayEnhMetaFile (hdc, hemf, &rcWindow);
|
|
|
|
|
|
|
|
// Always return TRUE. PlayEnhMetaFile() can return
|
|
// FALSE even when the metafile can be displayed
|
|
// properly. Things such as printer escap can cause
|
|
// the call to return FALSE when painting to screen
|
|
// but the image will be displayed fine.
|
|
//
|
|
// We return TRUE so we don't blank the display and
|
|
// put "Clipbook can't display..." message.
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* EnumMetafileProc
|
|
*
|
|
* Metafile record play callback function used to work around problem
|
|
* with non active MDI children playing a metafile that causes a foreground
|
|
* palette selection
|
|
*/
|
|
|
|
BOOL CALLBACK EnumMetafileProc (
|
|
HDC hdc,
|
|
HANDLETABLE FAR *lpht,
|
|
METARECORD FAR *lpmr,
|
|
int cObj,
|
|
LPARAM lParam )
|
|
{
|
|
if ( lpmr->rdFunction == META_SELECTPALETTE )
|
|
{
|
|
return SelectPalette ( hdc, lpht[(lpmr->rdParm[0])].objectHandle[0],
|
|
TRUE ) != NULL;
|
|
}
|
|
else
|
|
{
|
|
PlayMetaFileRecord ( hdc, lpht, lpmr, cObj );
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* FShowMetaFilePict
|
|
*
|
|
* Display a metafile in the specified rectangle.
|
|
*/
|
|
|
|
BOOL FShowMetaFilePict(
|
|
HWND hwnd,
|
|
register HDC hdc,
|
|
register PRECT prc,
|
|
HANDLE hmfp,
|
|
int cxScroll,
|
|
int cyScroll)
|
|
{
|
|
int level;
|
|
int cxBitmap;
|
|
int cyBitmap;
|
|
int f = FALSE;
|
|
LPMETAFILEPICT lpmfp;
|
|
PMDIINFO pMDI;
|
|
|
|
|
|
|
|
pMDI = GETMDIINFO(hwnd);
|
|
|
|
if (pMDI)
|
|
{
|
|
|
|
if ((lpmfp = (LPMETAFILEPICT)GlobalLock( hmfp )) != NULL)
|
|
{
|
|
METAFILEPICT mfp;
|
|
|
|
mfp = *lpmfp;
|
|
GlobalUnlock( hmfp );
|
|
|
|
if ((level = SaveDC( hdc )) != 0)
|
|
{
|
|
|
|
/* Compute size of picture to be displayed */
|
|
switch (mfp.mm)
|
|
{
|
|
case MM_ISOTROPIC:
|
|
case MM_ANISOTROPIC:
|
|
/* Not scrollable. Resize these into the given rect. */
|
|
pMDI->cyScrollLast = 0;
|
|
pMDI->cxScrollLast = 0;
|
|
cxBitmap = pMDI->rcWindow.right - pMDI->rcWindow.left;
|
|
cyBitmap = pMDI->rcWindow.bottom - pMDI->rcWindow.top;
|
|
break;
|
|
|
|
default:
|
|
cxBitmap = PxlConvert(mfp.mm, mfp.xExt, GetDeviceCaps(hdc, HORZRES), GetDeviceCaps(hdc, HORZSIZE));
|
|
cyBitmap = PxlConvert(mfp.mm, mfp.yExt, GetDeviceCaps(hdc, VERTRES), GetDeviceCaps(hdc, VERTSIZE));
|
|
if (!cxBitmap || !cyBitmap)
|
|
{
|
|
goto NoDisplay;
|
|
}
|
|
|
|
if ( pMDI->cxScrollLast == -1)
|
|
{
|
|
pMDI->cxScrollLast =
|
|
cxBitmap - (pMDI->rcWindow.right - pMDI->rcWindow.left);
|
|
if ( pMDI->cxScrollLast < 0)
|
|
{
|
|
pMDI->cxScrollLast = 0;
|
|
}
|
|
}
|
|
|
|
if (pMDI->cyScrollLast == -1)
|
|
{
|
|
pMDI->cyScrollLast =
|
|
cyBitmap - (pMDI->rcWindow.bottom - pMDI->rcWindow.top);
|
|
if (pMDI->cyScrollLast < 0)
|
|
{
|
|
pMDI->cyScrollLast = 0;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* We make the "viewport" to be an area the same size as the
|
|
* clipboard object, and set the origin and clip region so as
|
|
* to show the area we want. Note that the viewport may well be
|
|
* bigger than the window.
|
|
*/
|
|
SetMapMode(hdc, mfp.mm);
|
|
|
|
SetViewportOrgEx(hdc, prc->left - cxScroll, prc->top - cyScroll, NULL);
|
|
switch (mfp.mm)
|
|
{
|
|
case MM_ISOTROPIC:
|
|
if (mfp.xExt && mfp.yExt)
|
|
{
|
|
// So we get the correct shape rectangle when
|
|
// SetViewportExt gets called.
|
|
//
|
|
SetWindowExtEx(hdc, mfp.xExt, mfp.yExt, NULL);
|
|
}
|
|
// FALL THRU
|
|
|
|
case MM_ANISOTROPIC:
|
|
SetViewportExtEx(hdc, cxBitmap, cyBitmap, NULL);
|
|
break;
|
|
}
|
|
|
|
/* Since we may have scrolled, force brushes to align */
|
|
SetBrushOrgEx(hdc, cxScroll - prc->left, cyScroll - prc->top, NULL);
|
|
|
|
f = EnumMetaFile(hdc, mfp.hMF, EnumMetafileProc, 0L );
|
|
FreeProcInstance ( (FARPROC) lpEnumMetaProc );
|
|
|
|
NoDisplay:
|
|
RestoreDC(hdc, level);
|
|
}
|
|
}
|
|
}
|
|
|
|
return(f);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* ShowString
|
|
*
|
|
* Blank rcWindow and show the string on the top line of the client area
|
|
*/
|
|
|
|
void ShowString(
|
|
HWND hwnd,
|
|
HDC hdc,
|
|
WORD id)
|
|
{
|
|
TCHAR szBuffer[BUFFERLEN];
|
|
LPTSTR pszBuffer = szBuffer;
|
|
INT iBufferSize = BUFFERLEN;
|
|
|
|
INT iStringLen;
|
|
|
|
|
|
/* Cancel any scrolling effects. */
|
|
GETMDIINFO(hwnd)->cyScrollNow = 0;
|
|
GETMDIINFO(hwnd)->cxScrollNow = 0;
|
|
|
|
|
|
iStringLen = LoadString(hInst, id, pszBuffer, BUFFERLEN);
|
|
|
|
|
|
// Is the buffer completely filled out?
|
|
// We need a bigger one if yes.
|
|
|
|
while (iStringLen == BUFFERLEN -1)
|
|
{
|
|
if (pszBuffer != szBuffer && pszBuffer)
|
|
LocalFree (pszBuffer);
|
|
|
|
iBufferSize *= 2;
|
|
pszBuffer = LocalAlloc (LPTR, iBufferSize);
|
|
|
|
if (!pszBuffer)
|
|
goto done;
|
|
|
|
iStringLen = LoadString (hInst, id, pszBuffer, iBufferSize);
|
|
}
|
|
|
|
|
|
FillRect (hdc, &(GETMDIINFO(hwnd)->rcWindow), hbrBackground);
|
|
DrawText (hdc, pszBuffer, -1, &(GETMDIINFO(hwnd)->rcWindow),
|
|
DT_CENTER | DT_WORDBREAK | DT_TOP);
|
|
|
|
done:
|
|
|
|
if (pszBuffer != szBuffer && pszBuffer)
|
|
LocalFree (pszBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* CchLineA
|
|
*
|
|
*
|
|
* Determine the # of characters in one display line's worth of lpch.
|
|
* lpch is assumed to be an ansi string.
|
|
*
|
|
* Return the following:
|
|
* HI WORD: # of chars to display (excludes CR, LF; will not
|
|
* exceed cchLine)
|
|
* LO WORD: offset of start of next line in lpch; If the current line
|
|
* is NULL terminated, this contains offset to the NULL char;
|
|
* In RgchBuf: characters to display
|
|
*
|
|
* Expands Tabs
|
|
*
|
|
* Accepts any of the following as valid end-of-line terminators:
|
|
* CR, LF, CR-LF, LF-CR, NULL
|
|
* Callers may test for having reached NULL by (lpch[LOWORD] == '\0')
|
|
*/
|
|
|
|
LONG CchLineA(
|
|
PMDIINFO pMDI,
|
|
HDC hDC,
|
|
CHAR rgchBuf[],
|
|
CHAR FAR *lpch,
|
|
INT cchLine,
|
|
WORD wWidth)
|
|
{
|
|
CHAR ch;
|
|
CHAR *pch = rgchBuf;
|
|
register INT cchIn = 0;
|
|
register INT cchOut = 0;
|
|
INT iMinNoOfChars;
|
|
SIZE size;
|
|
INT iTextWidth = 0;
|
|
|
|
|
|
|
|
iMinNoOfChars = wWidth / pMDI->cxMaxCharWidth;
|
|
|
|
while (cchOut < cchLine)
|
|
{
|
|
switch (ch = *(lpch + (DWORD)cchIn++))
|
|
{
|
|
case '\0':
|
|
/* cchIn is already incremented; So, it is pointing to
|
|
* a character beyond the NULL; So, decrement it.
|
|
*/
|
|
cchIn--;
|
|
goto DoubleBreak;
|
|
|
|
case '\015': /* CR */
|
|
case '\012': /* LF */
|
|
if ((lpch[cchIn] == '\015') || (lpch[cchIn] == '\012'))
|
|
cchIn++;
|
|
goto DoubleBreak;
|
|
|
|
case '\011': /* TAB */
|
|
{
|
|
INT cchT = 8 - (cchOut % 8);
|
|
|
|
/* Check if the width has exceeded or the total
|
|
* number of characters has exceeded
|
|
*/
|
|
if (((WORD)(iTextWidth + cchT * pMDI->cxChar) > wWidth) || ((cchOut+cchT) >= cchLine))
|
|
/* Tab causes wrap to next line */
|
|
goto DoubleBreak;
|
|
|
|
while (cchT--)
|
|
rgchBuf[cchOut++] = ' ';
|
|
break;
|
|
}
|
|
|
|
default:
|
|
rgchBuf[cchOut++] = ch;
|
|
if( IsDBCSLeadByte(ch) )
|
|
rgchBuf[cchOut++] = *(lpch + (DWORD)cchIn++);
|
|
|
|
break;
|
|
}
|
|
|
|
/* Check if the width has been exceeded. */
|
|
if (cchOut >= iMinNoOfChars)
|
|
{
|
|
GetTextExtentPointA(hDC, rgchBuf, cchOut, (LPSIZE)&size);
|
|
iTextWidth = size.cx;
|
|
if ((WORD)iTextWidth == wWidth)
|
|
break;
|
|
else if((WORD)iTextWidth > wWidth)
|
|
{
|
|
if (IsDBCSLeadByte(ch))
|
|
{
|
|
cchOut--;
|
|
cchIn--;
|
|
}
|
|
|
|
cchOut--;
|
|
cchIn--;
|
|
break;
|
|
}
|
|
|
|
iMinNoOfChars += (wWidth - iTextWidth) / pMDI->cxMaxCharWidth;
|
|
}
|
|
}
|
|
|
|
|
|
DoubleBreak:
|
|
return(MAKELONG(cchIn, cchOut));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* */
|
|
/* CchLineW() - */
|
|
/* */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/*Same as previous function but takes unicode strings.
|
|
*/
|
|
|
|
LONG CchLineW(
|
|
PMDIINFO pMDI,
|
|
HDC hDC,
|
|
WCHAR rgchBuf[],
|
|
WCHAR FAR *lpch,
|
|
INT cchLine,
|
|
WORD wWidth)
|
|
{
|
|
register INT cchIn = 0;
|
|
register INT cchOut = 0;
|
|
WCHAR ch;
|
|
WCHAR *pch = rgchBuf;
|
|
INT iMinNoOfChars;
|
|
INT iTextWidth = 0;
|
|
SIZE size;
|
|
|
|
|
|
iMinNoOfChars = wWidth / pMDI->cxMaxCharWidth;
|
|
|
|
while (cchOut < cchLine)
|
|
{
|
|
switch (ch = *(lpch + (DWORD)cchIn++))
|
|
{
|
|
case L'\0':
|
|
/* cchIn is already incremented; So, it is pointing to
|
|
* a character beyond the NULL; So, decrement it.
|
|
*/
|
|
cchIn--;
|
|
goto DoubleBreak;
|
|
|
|
case L'\015': /* CR */
|
|
case L'\012': /* LF */
|
|
if ((lpch[cchIn] == L'\015') || (lpch[cchIn] == L'\012'))
|
|
cchIn++;
|
|
goto DoubleBreak;
|
|
|
|
case L'\011': /* TAB */
|
|
{
|
|
INT cchT = 8 - (cchOut % 8);
|
|
|
|
/* Check if the width has exceeded or the total
|
|
* number of characters has exceeded
|
|
*/
|
|
if (((WORD)(iTextWidth + cchT * pMDI->cxChar) > wWidth) || ((cchOut+cchT) >= cchLine))
|
|
/* Tab causes wrap to next line */
|
|
goto DoubleBreak;
|
|
|
|
while (cchT--)
|
|
rgchBuf[cchOut++] = L' ';
|
|
break;
|
|
}
|
|
|
|
default:
|
|
rgchBuf[cchOut++] = ch;
|
|
break;
|
|
}
|
|
|
|
|
|
/* Check if the width has been exceeded. */
|
|
if (cchOut >= iMinNoOfChars)
|
|
{
|
|
GetTextExtentPointW(hDC, rgchBuf, cchOut, &size);
|
|
iTextWidth = size.cx;
|
|
if ((WORD)iTextWidth == wWidth)
|
|
break;
|
|
else if((WORD)iTextWidth > wWidth)
|
|
{
|
|
cchOut--;
|
|
cchIn--;
|
|
break;
|
|
}
|
|
|
|
iMinNoOfChars += (wWidth - iTextWidth) / pMDI->cxMaxCharWidth;
|
|
}
|
|
}
|
|
|
|
|
|
DoubleBreak:
|
|
|
|
return(MAKELONG(cchIn, cchOut));
|
|
|
|
}
|
|
|
|
|
|
|
|
#define cchLineMax 200
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* */
|
|
/* ShowText() - */
|
|
/* */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
void ShowText(
|
|
HWND hwnd,
|
|
register HDC hdc,
|
|
PRECT prc,
|
|
HANDLE h,
|
|
INT cyScroll,
|
|
BOOL fUnicode)
|
|
{
|
|
|
|
CHAR FAR *lpch;
|
|
INT yT;
|
|
INT cLine;
|
|
INT cLineAllText = 0;
|
|
RECT rc;
|
|
INT yLine;
|
|
INT iLineFirstShow;
|
|
WORD wLen;
|
|
WORD wWidth;
|
|
CHAR rgch[cchLineMax*sizeof(WCHAR)];
|
|
PMDIINFO pMDI;
|
|
|
|
|
|
|
|
pMDI= GETMDIINFO(hwnd);
|
|
|
|
rc = *prc;
|
|
|
|
/* Expand repaint rectangle as necessary to hold an exact number of
|
|
* lines and start on an even line boundary. This is because we may
|
|
* get arbitrarily weird repaint rectangles when popups are moved.
|
|
* Scrolling repaint areas should require no adjustment.
|
|
*/
|
|
|
|
rc.top -= (rc.top - pMDI->rcWindow.top) % pMDI->cyLine;
|
|
|
|
|
|
|
|
/* If expanding the repaint rectangle to the next line expands it */
|
|
/* beyond the bottom of my window, contract it one line. */
|
|
if ((yT = (rc.bottom - rc.top) % pMDI->cyLine) != 0)
|
|
if ((rc.bottom += pMDI->cyLine - yT) > pMDI->rcWindow.bottom)
|
|
rc.bottom -= pMDI->cyLine;
|
|
|
|
if (rc.bottom <= rc.top)
|
|
return;
|
|
|
|
if (((wWidth = (WORD)(pMDI->rcWindow.right - pMDI->rcWindow.left)) <= 0) ||
|
|
((cLine = (rc.bottom - rc.top) / pMDI->cyLine) <= 0) ||
|
|
(NULL == (lpch = (LPSTR)GlobalLock(h))) )
|
|
{
|
|
/* Bad Rectangle or Bad Text Handle */
|
|
ShowString(hwnd, hdc, IDS_ERROR);
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/* Advance lpch to point at the text for the first line to show. */
|
|
iLineFirstShow = cyScroll / pMDI->cyLine;
|
|
|
|
|
|
/* Advance lpch to point at text for that line. */
|
|
if (!fUnicode)
|
|
while ((*lpch) && (iLineFirstShow--))
|
|
{
|
|
lpch += LOWORD(CchLineA(pMDI,hdc, rgch, lpch, cchLineMax, wWidth));
|
|
cLineAllText++;
|
|
}
|
|
else
|
|
while ((*((WCHAR *)lpch)) && (iLineFirstShow--))
|
|
{
|
|
lpch += ((LOWORD(CchLineW(pMDI, hdc, (WCHAR *)rgch, (WCHAR FAR *)lpch,
|
|
cchLineMax, wWidth)))*sizeof(WCHAR));
|
|
cLineAllText++;
|
|
}
|
|
|
|
|
|
/* Display string, line by line */
|
|
yLine = rc.top;
|
|
while (cLine--)
|
|
{
|
|
LONG lT;
|
|
|
|
if (!fUnicode)
|
|
{
|
|
lT = CchLineA(pMDI, hdc, rgch, lpch, cchLineMax, wWidth);
|
|
}
|
|
else
|
|
{
|
|
lT = CchLineW(pMDI, hdc, (WCHAR *)rgch, (WCHAR FAR *)lpch, cchLineMax, wWidth);
|
|
}
|
|
wLen = LOWORD(lT);
|
|
if (!fUnicode)
|
|
{
|
|
TextOutA(hdc, rc.left, yLine, (LPSTR) rgch, HIWORD(lT));
|
|
lpch += wLen;
|
|
}
|
|
else
|
|
{
|
|
if (!TextOutW(hdc, rc.left, yLine, (LPCWSTR) rgch, HIWORD(lT)))
|
|
{
|
|
GetLastError();
|
|
}
|
|
lpch += (wLen * sizeof(WCHAR));
|
|
}
|
|
yLine += pMDI->cyLine;
|
|
cLineAllText++;
|
|
if ((!fUnicode && (*lpch == 0)) || (fUnicode && (*((WCHAR *)lpch) == L'\0')))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
if (pMDI->cxScrollLast == -1)
|
|
{
|
|
/* We don't use horiz scroll for text */
|
|
pMDI->cxScrollLast = 0;
|
|
}
|
|
|
|
if (pMDI->cyScrollLast == -1)
|
|
{
|
|
INT cLineInRcWindow;
|
|
|
|
/* Validate y-size of text in clipboard. */
|
|
/* Adjust rcWindow dimensions for text display */
|
|
cLineInRcWindow = (pMDI->rcWindow.bottom - pMDI->rcWindow.top) / pMDI->cyLine;
|
|
|
|
do {
|
|
if (!fUnicode)
|
|
{
|
|
lpch += LOWORD(CchLineA(pMDI, hdc, rgch, lpch, cchLineMax, wWidth));
|
|
}
|
|
else
|
|
{
|
|
lpch += ((LOWORD(CchLineW(pMDI, hdc, (WCHAR *)rgch,
|
|
(WCHAR FAR *)lpch, cchLineMax, wWidth)))*sizeof(WCHAR));
|
|
}
|
|
cLineAllText++;
|
|
}
|
|
while ((!fUnicode && (*lpch != 0)) || (fUnicode && ((*lpch != 0) || (*(lpch+1) != 0))));
|
|
|
|
pMDI->cyScrollLast = (cLineAllText - cLineInRcWindow) * pMDI->cyLine;
|
|
if (pMDI->cyScrollLast < 0)
|
|
{
|
|
pMDI->cyScrollLast = 0;
|
|
}
|
|
|
|
/* Restrict rcWindow so that it holds an exact # of text lines */
|
|
pMDI->rcWindow.bottom = pMDI->rcWindow.top + (cLineInRcWindow * pMDI->cyLine);
|
|
}
|
|
|
|
|
|
GlobalUnlock(h);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* SendOwnerMessage
|
|
*/
|
|
|
|
void SendOwnerMessage(
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
register HWND hwndOwner;
|
|
|
|
/* Send a message to the clipboard owner, if there is one */
|
|
hwndOwner = GetClipboardOwner();
|
|
|
|
if (hwndOwner != NULL)
|
|
SendMessage(hwndOwner, message, wParam, lParam);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* SendOwnerSizeMessage
|
|
*
|
|
* Send WM_SIZECLIPBOARD message to clipboard owner.
|
|
* wParam is a handle to the clipboard window
|
|
* LOWORD(lParam) is a handle to the passed rect
|
|
*/
|
|
|
|
void SendOwnerSizeMessage (
|
|
HWND hwnd,
|
|
int left,
|
|
int top,
|
|
int right,
|
|
int bottom)
|
|
{
|
|
register HANDLE hrc;
|
|
LPRECT lprc;
|
|
|
|
|
|
|
|
if ((hrc = GlobalAlloc (GMEM_MOVEABLE | GMEM_LOWER, (LONG)sizeof(RECT))) != NULL )
|
|
{
|
|
if ((lprc = (LPRECT)GlobalLock(hrc)) != NULL )
|
|
{
|
|
lprc->top = top;
|
|
lprc->bottom = bottom;
|
|
lprc->left = left;
|
|
lprc->right = right;
|
|
GlobalUnlock(hrc);
|
|
SendOwnerMessage(WM_SIZECLIPBOARD, (WPARAM)hwnd, (LPARAM)hrc);
|
|
}
|
|
GlobalFree(hrc);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* GetBestFormat
|
|
*
|
|
* This routine decides which one of the existing formats is to be
|
|
* displayed in the viewer.
|
|
*/
|
|
|
|
UINT GetBestFormat(
|
|
HWND hwnd,
|
|
UINT wFormat)
|
|
{
|
|
register WORD cFmt;
|
|
register WORD *pfmt;
|
|
|
|
|
|
// PINFO(TEXT("GBFormat %d\r\n"), wFormat);
|
|
|
|
if (wFormat == CBM_AUTO)
|
|
{
|
|
for (cFmt=ifmtMax, pfmt=&rgfmt[0]; cFmt--; pfmt++)
|
|
{
|
|
// PINFO(TEXT("Looking at # %d, (%d)\r\n"), cFmt, *pfmt);
|
|
if ( VIsClipboardFormatAvailable( GETMDIINFO(hwnd)->pVClpbrd, *pfmt ))
|
|
{
|
|
return(*pfmt);
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
return(wFormat);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* GetClipboardName
|
|
*/
|
|
|
|
void GetClipboardName (
|
|
register int fmt,
|
|
LPTSTR szName,
|
|
register int iSize)
|
|
{
|
|
LPTSTR lprgch;
|
|
HANDLE hrgch;
|
|
|
|
|
|
|
|
*szName = '\0';
|
|
|
|
|
|
/* Get global memory that everyone can get to */
|
|
if ((hrgch = GlobalAlloc(GMEM_MOVEABLE | GMEM_LOWER, (LONG)(iSize + 1))) == NULL)
|
|
{
|
|
PERROR(TEXT("GetClipboardName: alloc failure\n\r"));
|
|
return;
|
|
}
|
|
|
|
if (!(lprgch = (LPTSTR)GlobalLock(hrgch)))
|
|
goto ExitPoint;
|
|
|
|
switch (fmt)
|
|
{
|
|
// These are all of the formats we have know the names of.
|
|
case CF_RIFF:
|
|
case CF_WAVE:
|
|
case CF_PENDATA:
|
|
case CF_SYLK:
|
|
case CF_DIF:
|
|
case CF_TIFF:
|
|
|
|
case CF_TEXT:
|
|
case CF_UNICODETEXT:
|
|
case CF_OEMTEXT:
|
|
case CF_DSPTEXT:
|
|
case CF_LOCALE:
|
|
|
|
case CF_BITMAP:
|
|
case CF_DIB:
|
|
case CF_PALETTE:
|
|
case CF_DSPBITMAP:
|
|
|
|
case CF_METAFILEPICT:
|
|
case CF_DSPMETAFILEPICT:
|
|
case CF_ENHMETAFILE:
|
|
case CF_DSPENHMETAFILE:
|
|
case CF_HDROP:
|
|
LoadString(hInst, fmt, lprgch, iSize);
|
|
break;
|
|
|
|
case CF_OWNERDISPLAY: /* Clipbrd owner app supplies name */
|
|
*lprgch = '\0';
|
|
SendOwnerMessage(WM_ASKCBFORMATNAME, (WPARAM)iSize, (LPARAM)(LPSTR)lprgch);
|
|
|
|
if (!*lprgch)
|
|
LoadString(hInst, fmt, lprgch, iSize);
|
|
break;
|
|
|
|
default:
|
|
*lprgch = '\0';
|
|
GetClipboardFormatName(fmt, lprgch, iSize);
|
|
break;
|
|
}
|
|
|
|
StringCchCopy(szName, iSize, lprgch);
|
|
|
|
GlobalUnlock(hrgch);
|
|
|
|
|
|
ExitPoint:
|
|
GlobalFree(hrgch);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* GetClipboardMenuName
|
|
*/
|
|
|
|
void GetClipboardMenuName (
|
|
register int fmt,
|
|
LPTSTR szName,
|
|
register int iSize)
|
|
{
|
|
LPTSTR lprgch;
|
|
HANDLE hrgch;
|
|
|
|
|
|
|
|
*szName = '\0';
|
|
|
|
|
|
/* Get global memory that everyone can get to */
|
|
if ((hrgch = GlobalAlloc(GMEM_MOVEABLE | GMEM_LOWER, (LONG)(iSize + 1))) == NULL)
|
|
{
|
|
PERROR(TEXT("GetClipboardName: alloc failure\n\r"));
|
|
return;
|
|
}
|
|
|
|
if (!(lprgch = (LPTSTR)GlobalLock(hrgch)))
|
|
goto ExitPoint;
|
|
|
|
switch (fmt)
|
|
{
|
|
// These are all of the formats we have know the names of.
|
|
case CF_RIFF:
|
|
case CF_WAVE:
|
|
case CF_PENDATA:
|
|
case CF_SYLK:
|
|
case CF_DIF:
|
|
case CF_TIFF:
|
|
|
|
case CF_TEXT:
|
|
case CF_UNICODETEXT:
|
|
case CF_OEMTEXT:
|
|
case CF_DSPTEXT:
|
|
|
|
case CF_BITMAP:
|
|
case CF_DIB:
|
|
case CF_PALETTE:
|
|
case CF_DSPBITMAP:
|
|
|
|
case CF_METAFILEPICT:
|
|
case CF_DSPMETAFILEPICT:
|
|
case CF_ENHMETAFILE:
|
|
case CF_DSPENHMETAFILE:
|
|
|
|
case CF_HDROP:
|
|
case CF_LOCALE:
|
|
LoadString(hInst, fmt+MNDELTA, lprgch, iSize);
|
|
break;
|
|
|
|
case CF_OWNERDISPLAY: /* Clipbrd owner app supplies name */
|
|
*lprgch = '\0';
|
|
SendOwnerMessage(WM_ASKCBFORMATNAME, (WPARAM)iSize, (LPARAM)(LPSTR)lprgch);
|
|
|
|
if (!*lprgch)
|
|
LoadString(hInst, CF_MN_OWNERDISPLAY, lprgch, iSize);
|
|
break;
|
|
|
|
default:
|
|
GetClipboardFormatName(fmt, lprgch, iSize);
|
|
break;
|
|
}
|
|
|
|
StringCchCopy(szName, iSize, lprgch);
|
|
|
|
GlobalUnlock(hrgch);
|
|
|
|
|
|
ExitPoint:
|
|
GlobalFree(hrgch);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* DrawFormat
|
|
*
|
|
* Parameters:
|
|
* hdc - the hdc to draw in.
|
|
* prc - The rectangle to paint
|
|
* cxScroll - The scroll position of the window.
|
|
* cyScroll - The scroll position OF THE PAINT RECTANGLE. NOT THE WINDOW.
|
|
* (Gawd. Who DESIGNED this?) Measured in pels.
|
|
* BestFormat - The format to draw.
|
|
* hwndMDI - The window we're drawing in.
|
|
*
|
|
*/
|
|
|
|
void DrawFormat(
|
|
register HDC hdc,
|
|
PRECT prc,
|
|
int cxScroll,
|
|
int cyScroll,
|
|
WORD BestFormat,
|
|
HWND hwndMDI)
|
|
{
|
|
register HANDLE h;
|
|
HFONT hFont;
|
|
int fOK = TRUE;
|
|
WORD wFormat = 0;
|
|
PMDIINFO pMDI;
|
|
|
|
|
|
|
|
pMDI = GETMDIINFO(hwndMDI);
|
|
|
|
PINFO(TEXT("DrawFormat: (%d, %d), %d"), cxScroll, cyScroll, BestFormat);
|
|
|
|
if (hwndMDI == hwndClpbrd && pMDI->pVClpbrd)
|
|
{
|
|
PERROR(TEXT("Clipboard window shouldn't have vClp!\r\n"));
|
|
}
|
|
|
|
|
|
/* If "Auto" is chosen and only data in unrecognised formats is
|
|
* available, then display "Can't display data in this format".
|
|
*/
|
|
if ((BestFormat == 0) &&
|
|
VCountClipboardFormats( pMDI->pVClpbrd ))
|
|
{
|
|
if ((wFormat = (WORD)RegisterClipboardFormat(TEXT("FileName"))) &&
|
|
VIsClipboardFormatAvailable(pMDI->pVClpbrd, wFormat))
|
|
{
|
|
BestFormat = CF_TEXT;
|
|
}
|
|
else
|
|
{
|
|
PINFO(TEXT("no displayable format\n\r"));
|
|
ShowString( hwndMDI, hdc, IDS_CANTDISPLAY);
|
|
return;
|
|
}
|
|
}
|
|
|
|
PINFO(TEXT("format %x\n\r"), BestFormat);
|
|
|
|
h = VGetClipboardData( pMDI->pVClpbrd, wFormat ? wFormat : BestFormat );
|
|
|
|
|
|
if ( h != NULL)
|
|
{
|
|
PINFO(TEXT("Got format %x from VGetClipboardData\n\r"), BestFormat );
|
|
|
|
switch (BestFormat)
|
|
{
|
|
|
|
case CF_DSPTEXT:
|
|
case CF_TEXT:
|
|
ShowText( hwndMDI, hdc, prc, h, cyScroll, FALSE);
|
|
break;
|
|
|
|
case CF_UNICODETEXT:
|
|
hFont = SelectObject(hdc, hfontUni);
|
|
ShowText(hwndMDI, hdc, prc, h, cyScroll, TRUE);
|
|
SelectObject(hdc, hFont);
|
|
break;
|
|
|
|
case CF_OEMTEXT:
|
|
hFont = SelectObject(hdc, GetStockObject ( OEM_FIXED_FONT ) );
|
|
ShowText(hwndMDI, hdc, prc, h, cyScroll, FALSE);
|
|
SelectObject(hdc, hFont);
|
|
break;
|
|
|
|
case CF_DSPBITMAP:
|
|
case CF_BITMAP:
|
|
fOK = FShowBitmap( hwndMDI, hdc, prc, h, cxScroll, cyScroll);
|
|
break;
|
|
|
|
case CF_DIB:
|
|
fOK = FShowDIBitmap( hwndMDI, hdc, prc, h, cxScroll, cyScroll);
|
|
break;
|
|
|
|
case CF_PALETTE:
|
|
fOK = FShowPalette( hwndMDI, hdc, prc, h, cxScroll, cyScroll);
|
|
break;
|
|
|
|
case CF_WAVE:
|
|
case CF_RIFF:
|
|
case CF_PENDATA:
|
|
case CF_DIF:
|
|
case CF_SYLK:
|
|
case CF_TIFF:
|
|
case CF_LOCALE:
|
|
ShowString( hwndMDI, hdc, IDS_BINARY);
|
|
break;
|
|
|
|
case CF_DSPMETAFILEPICT:
|
|
case CF_METAFILEPICT:
|
|
fOK = FShowMetaFilePict( hwndMDI, hdc, prc, h, cxScroll, cyScroll);
|
|
break;
|
|
|
|
case CF_DSPENHMETAFILE:
|
|
case CF_ENHMETAFILE:
|
|
fOK = FShowEnhMetaFile( hwndMDI, hdc, prc, h, cxScroll, cyScroll);
|
|
break;
|
|
|
|
default:
|
|
ShowString( hwndMDI, hdc, IDS_BINARY);
|
|
break;
|
|
}
|
|
|
|
// Disable scroll bars that don't work
|
|
EnableWindow(pMDI->hwndVscroll, pMDI->cyScrollLast > 1 ? TRUE : FALSE);
|
|
EnableWindow(pMDI->hwndHscroll, pMDI->cxScrollLast > 1 ? TRUE : FALSE);
|
|
}
|
|
else
|
|
{
|
|
PERROR(TEXT("VGetClpDta fail\r\n"));
|
|
}
|
|
|
|
/* Check if the Data was not rendered by the application */
|
|
if ((h == NULL) &&
|
|
VCountClipboardFormats( pMDI->pVClpbrd ))
|
|
{
|
|
ShowString( hwndMDI, hdc, IDS_NOTRENDERED);
|
|
}
|
|
else
|
|
{
|
|
/* If we are unable to display the data, display "<Error>" */
|
|
if (!fOK)
|
|
{
|
|
ShowString( hwndMDI, hdc, IDS_ERROR);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* DrawStuff
|
|
*
|
|
* Paint portion of current clipboard contents given by PAINT struct
|
|
* NOTE: If the paintstruct rectangle includes any part of the header, the
|
|
* whole header is redrawn.
|
|
*/
|
|
|
|
void DrawStuff(
|
|
HWND hwnd,
|
|
register PAINTSTRUCT *pps,
|
|
HWND hwndMDI)
|
|
{
|
|
register HDC hdc;
|
|
RECT rcPaint;
|
|
RECT rcClient;
|
|
WORD BestFormat;
|
|
PMDIINFO pMDI;
|
|
|
|
|
|
|
|
pMDI = GETMDIINFO(hwnd);
|
|
|
|
if (pMDI)
|
|
{
|
|
hdc = pps->hdc;
|
|
|
|
|
|
if (pps->fErase)
|
|
FillRect(hdc, (LPRECT)&pps->rcPaint, hbrBackground);
|
|
|
|
GetClientRect(hwnd, (LPRECT)&rcClient);
|
|
|
|
|
|
// make room for scroll controls:
|
|
|
|
BestFormat = (WORD)GetBestFormat( hwnd, pMDI->CurSelFormat );
|
|
|
|
fOwnerDisplay = (BestFormat == CF_OWNERDISPLAY);
|
|
|
|
if ( !fOwnerDisplay )
|
|
{
|
|
ShowScrollBar ( hwnd, SB_BOTH, FALSE );
|
|
rcClient.right -= GetSystemMetrics ( SM_CXVSCROLL );
|
|
rcClient.bottom -= GetSystemMetrics ( SM_CYHSCROLL );
|
|
}
|
|
|
|
|
|
/* If the display format has changed, Set rcWindow,
|
|
* the display area for clip info.
|
|
*/
|
|
|
|
if ( pMDI->fDisplayFormatChanged )
|
|
{
|
|
CopyRect((LPRECT)&(pMDI->rcWindow), (LPRECT)&rcClient);
|
|
|
|
/* We have changed the size of the clipboard. Tell the owner,
|
|
* if fOwnerDisplay is active.
|
|
*/
|
|
|
|
if (fOwnerDisplay)
|
|
{
|
|
SendOwnerSizeMessage(hwnd,
|
|
pMDI->rcWindow.left,
|
|
pMDI->rcWindow.top,
|
|
pMDI->rcWindow.right,
|
|
pMDI->rcWindow.bottom);
|
|
}
|
|
else
|
|
{
|
|
/* Give the window a small margin, for looks */
|
|
InflateRect (&(pMDI->rcWindow),
|
|
-(int)(pMDI->cxMargin),
|
|
-(int)(pMDI->cyMargin));
|
|
}
|
|
|
|
pMDI->fDisplayFormatChanged = FALSE;
|
|
}
|
|
|
|
if (fOwnerDisplay)
|
|
{
|
|
/* Clipboard Owner handles display */
|
|
HANDLE hps;
|
|
|
|
hps = GlobalAlloc(GMEM_MOVEABLE | GMEM_LOWER, (LONG)sizeof(PAINTSTRUCT));
|
|
|
|
if (hps != NULL)
|
|
{
|
|
LPPAINTSTRUCT lppsT;
|
|
|
|
if ((lppsT = (LPPAINTSTRUCT)GlobalLock(hps)) != NULL)
|
|
{
|
|
*lppsT = *pps;
|
|
IntersectRect(&lppsT->rcPaint, &pps->rcPaint, &(pMDI->rcWindow));
|
|
GlobalUnlock(hps);
|
|
SendOwnerMessage(WM_PAINTCLIPBOARD, (WPARAM)hwnd, (LPARAM)hps);
|
|
GlobalFree(hps);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* We handle display */
|
|
/* Redraw the portion of the paint rectangle that is in the clipbrd rect */
|
|
IntersectRect(&rcPaint, &pps->rcPaint, &(pMDI->rcWindow));
|
|
|
|
/* Always draw from left edge of window */
|
|
rcPaint.left = pMDI->rcWindow.left;
|
|
|
|
if ((rcPaint.bottom > rcPaint.top) && (rcPaint.right > rcPaint.left))
|
|
{
|
|
DrawFormat (hdc,
|
|
&rcPaint,
|
|
(int)(pMDI->cxScrollNow),
|
|
(int)(pMDI->cyScrollNow + rcPaint.top - pMDI->rcWindow.top),
|
|
BestFormat,
|
|
hwndMDI );
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* SaveOwnerScrollInfo
|
|
*
|
|
* When the user switched the clipboard display from owner disp to
|
|
* a non-owner display, all the information about the scroll bar
|
|
* positions are to be saved. This routine does that.
|
|
* This is required because, when the user returns back to owner
|
|
* display, the scroll bar positions are to be restored.
|
|
*/
|
|
|
|
void SaveOwnerScrollInfo (
|
|
register HWND hwnd)
|
|
|
|
{
|
|
GetScrollRange (hwnd, SB_VERT, (LPINT) & OwnVerMin, (LPINT) & OwnVerMax);
|
|
GetScrollRange (hwnd, SB_HORZ, (LPINT) & OwnHorMin, (LPINT) & OwnHorMax);
|
|
|
|
OwnVerPos = GetScrollPos( hwnd, SB_VERT );
|
|
OwnHorPos = GetScrollPos( hwnd, SB_HORZ );
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* RestoreOwnerScrollInfo
|
|
*
|
|
* When the user sitches back to owner-display, the scroll bar
|
|
* positions are restored by this routine.
|
|
*/
|
|
|
|
void RestoreOwnerScrollInfo (
|
|
register HWND hwnd)
|
|
|
|
{
|
|
PINFO(TEXT("SETSCROLLRANGE in RestoreOwnerScrollInfo\n\r"));
|
|
SetScrollRange( hwnd, SB_VERT, OwnVerMin, OwnVerMax, FALSE);
|
|
SetScrollRange( hwnd, SB_HORZ, OwnHorMin, OwnHorMax, FALSE);
|
|
|
|
SetScrollPos( hwnd, SB_VERT, OwnVerPos, TRUE);
|
|
SetScrollPos( hwnd, SB_HORZ, OwnHorPos, TRUE);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* InitOwnerScrollInfo
|
|
*/
|
|
|
|
void InitOwnerScrollInfo(void)
|
|
|
|
{
|
|
OwnVerPos = OwnHorPos = OwnVerMin = OwnHorMin = 0;
|
|
OwnVerMax = VPOSLAST;
|
|
OwnHorMax = HPOSLAST;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* UpdateCBMenu
|
|
*
|
|
* This routine is called once during initialisation and everytime
|
|
* the contents of the clipboard change. This updates the entries
|
|
* in the "Display" popup menu and the "grey" and "checked" status
|
|
* based on the data formats available in the clipboard.
|
|
*/
|
|
void UpdateCBMenu(
|
|
HWND hwnd,
|
|
HWND hwndMDI)
|
|
{
|
|
register WORD wFlags; // Used to store the status flags for menu items
|
|
register UINT fmt;
|
|
WORD cFmt;
|
|
WORD cCBCount; // Number of data items in CB
|
|
int iIndex;
|
|
int nPopupCount;
|
|
BOOL bAutoSelect;
|
|
TCHAR szName[40];
|
|
|
|
|
|
|
|
// Now clipboard contains at least one item...
|
|
// Find out the number entries in the popup menu at present.
|
|
|
|
// make sure child window is valid
|
|
if ( !hwndMDI || !IsWindow(hwndMDI))
|
|
{
|
|
PERROR(TEXT("bad window arg to UpdateCBMenu\n\r"));
|
|
return;
|
|
}
|
|
|
|
nPopupCount = GetMenuItemCount(hDispMenu);
|
|
|
|
if (nPopupCount > 6)
|
|
{
|
|
// Delete all the entries in the popup menu below menu break. */
|
|
for (iIndex = 6; iIndex < nPopupCount; iIndex++)
|
|
{
|
|
// NOTE: The second parameter must always be 6! (because we use
|
|
// MF_BYPOSITION, when 6 is deleted, 7 becomes 6!).
|
|
DeleteMenu(hDispMenu, 6, MF_BYPOSITION | MF_DELETE);
|
|
}
|
|
}
|
|
|
|
|
|
// If this is not a page MDI window we don't want to show any entries
|
|
if ( GETMDIINFO(hwndMDI)->DisplayMode != DSP_PAGE )
|
|
{
|
|
return;
|
|
}
|
|
|
|
bAutoSelect = TRUE;
|
|
|
|
|
|
|
|
if ((cCBCount = (WORD)VCountClipboardFormats( GETMDIINFO(hwndMDI)->pVClpbrd ))
|
|
&& VOpenClipboard( GETMDIINFO(hwndMDI)->pVClpbrd, hwnd))
|
|
{
|
|
AppendMenu ( hDispMenu, MF_SEPARATOR, 0, 0 );
|
|
AppendMenu ( hDispMenu, MF_STRING, CBM_AUTO, szDefaultFormat );
|
|
AppendMenu ( hDispMenu, MF_SEPARATOR, 0, 0 );
|
|
|
|
for (fmt=0, cFmt=1; cFmt <= cCBCount; cFmt++)
|
|
{
|
|
wFlags = 0;
|
|
fmt = VEnumClipboardFormats( GETMDIINFO(hwndMDI)->pVClpbrd, fmt );
|
|
|
|
// don't show preview format in menu...
|
|
if ( fmt != cf_preview )
|
|
{
|
|
switch (fmt)
|
|
{
|
|
case CF_TEXT:
|
|
case CF_OEMTEXT:
|
|
case CF_DSPTEXT:
|
|
case CF_UNICODETEXT:
|
|
case CF_DSPBITMAP:
|
|
|
|
case CF_DIB:
|
|
case CF_BITMAP:
|
|
|
|
case CF_METAFILEPICT:
|
|
case CF_DSPMETAFILEPICT:
|
|
case CF_ENHMETAFILE:
|
|
case CF_DSPENHMETAFILE:
|
|
|
|
case CF_OWNERDISPLAY:
|
|
case CF_PALETTE:
|
|
case CF_HDROP:
|
|
case CF_LOCALE:
|
|
|
|
/* can display all of these, put them on menu */
|
|
|
|
// Check if the current format is the one selected by the user
|
|
if (GETMDIINFO(hwndMDI)->CurSelFormat == fmt)
|
|
{
|
|
bAutoSelect = FALSE;
|
|
wFlags |= MF_CHECKED;
|
|
}
|
|
|
|
GetClipboardMenuName(fmt, szName, sizeof(szName));
|
|
AppendMenu (hDispMenu, wFlags, fmt, (LPTSTR)szName);
|
|
|
|
break;
|
|
|
|
default: /* all the rest... later */
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
for (fmt=VEnumClipboardFormats (GETMDIINFO(hwndMDI)->pVClpbrd, 0);
|
|
fmt;
|
|
fmt=VEnumClipboardFormats (GETMDIINFO(hwndMDI)->pVClpbrd, fmt))
|
|
if ( fmt != cf_preview )
|
|
switch (fmt)
|
|
{
|
|
case CF_TEXT:
|
|
case CF_OEMTEXT:
|
|
case CF_DSPTEXT:
|
|
case CF_UNICODETEXT:
|
|
case CF_DSPBITMAP:
|
|
case CF_DIB:
|
|
case CF_BITMAP:
|
|
case CF_METAFILEPICT:
|
|
case CF_DSPMETAFILEPICT:
|
|
case CF_ENHMETAFILE:
|
|
case CF_DSPENHMETAFILE:
|
|
case CF_OWNERDISPLAY:
|
|
case CF_PALETTE:
|
|
case CF_HDROP:
|
|
case CF_LOCALE:
|
|
break;
|
|
|
|
default:
|
|
/* can't display this, put it on menu and gray it */
|
|
|
|
GetClipboardName(fmt, szName, sizeof(szName));
|
|
AppendMenu (hDispMenu, MF_GRAYED, fmt, (LPTSTR)szName);
|
|
|
|
// NTRAID#DB-344956-2001/04/14-mdesai : add support for V5 bitmaps requires new strings, help changes, code to convert, etc
|
|
// clipbrd was adding an empty string for this format; now we ignore the format
|
|
case CF_DIBV5:
|
|
break;
|
|
}
|
|
|
|
VCloseClipboard( GETMDIINFO(hwndMDI)->pVClpbrd );
|
|
|
|
if (bAutoSelect)
|
|
{
|
|
GETMDIINFO(hwndMDI)->CurSelFormat = CBM_AUTO;
|
|
CheckMenuItem(hDispMenu, CBM_AUTO, MF_BYCOMMAND | MF_CHECKED);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PERROR(TEXT("UpdateCBMenu:couldn't open clip, or no data on clip\r\n"));
|
|
}
|
|
|
|
DrawMenuBar(hwnd);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* ClearClipboard
|
|
*
|
|
* This is called to clear the clipboard. If the clipboard is not
|
|
* empty the user is asked if it should be cleared.
|
|
*/
|
|
|
|
BOOL ClearClipboard (
|
|
register HWND hwnd)
|
|
|
|
{
|
|
register int RetVal;
|
|
|
|
if (CountClipboardFormats() <= 0)
|
|
return(TRUE);
|
|
|
|
if ( MessageBoxID( hInst, hwnd, IDS_CONFIRMCLEAR, IDS_CLEARTITLE,
|
|
MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
|
|
{
|
|
if (RetVal = SyncOpenClipboard(hwnd))
|
|
{
|
|
// PINFO("ClearClipboard: emptied clipboard\r\n");
|
|
RetVal &= EmptyClipboard();
|
|
RetVal &= SyncCloseClipboard();
|
|
}
|
|
else
|
|
{
|
|
// PERROR("ClearClipboard: could not open\r\n");
|
|
|
|
MessageBoxID (hInst,
|
|
hwnd,
|
|
IDS_CLEAR,
|
|
IDS_ERROR,
|
|
MB_OK | MB_SYSTEMMODAL | MB_ICONHAND);
|
|
}
|
|
|
|
InvalidateRect(hwnd, NULL, TRUE);
|
|
return RetVal;
|
|
}
|
|
|
|
return(FALSE);
|
|
|
|
}
|