|
|
#include "stdafx.h"
#include "global.h"
#include "pbrush.h"
#include "pbrusdoc.h"
#include "pbrusfrm.h"
#include "pbrusvw.h"
#include "minifwnd.h"
#include "bmobject.h"
#include "imgsuprt.h"
#include "imgwnd.h"
#include "imgwell.h"
#include "imgtools.h"
#include "t_fhsel.h"
#include "toolbox.h"
#include "imgbrush.h"
#include "imgdlgs.h"
#ifdef _DEBUG
#undef THIS_FILE
static CHAR BASED_CODE THIS_FILE[] = __FILE__; #endif // _DEBUG
#include "memtrace.h"
BOOL g_bUseTrans = FALSE; BOOL g_bCustomBrush = FALSE; BOOL fDraggingBrush = FALSE; IMG* pImgCur = NULL;
#define NUM_DEF_COLORS 28
extern COLORREF colorColorsDef[NUM_DEF_COLORS];
COLORREF crLeft = 0; COLORREF crRight = RGB( 0xff, 0xff, 0xff ); COLORREF crTrans = TRANS_COLOR_NONE; // transparent color
int theLeft; int theRight; int theTrans; int wCombineMode;
HDC hRubberDC; HBITMAP hRubberBM; int cxRubberWidth; int cyRubberHeight; IMG* pRubberImg;
BOOL EnsureUndoSize(IMG* pImg);
static int cxUndoWidth, cyUndoHeight; static BYTE cUndoPlanes, cUndoBitCount;
HBITMAP g_hUndoImgBitmap = NULL; HPALETTE g_hUndoPalette = NULL;
COLORREF std2Colors [] = { RGB(000, 000, 000), // 0 - black
RGB(255, 255, 255) // 1 - white
};
COLORREF std16Colors [] = { RGB( 0, 0, 0), // Black
RGB(128, 0, 0), // Dark Red
RGB( 0, 128, 0), // Dark Green
RGB(128, 128, 0), // Pea Green
RGB( 0, 0, 128), // Dark Blue
RGB(128, 0, 128), // Lavender
RGB( 0, 128, 128), // Slate
RGB(192, 192, 192), // Light Gray
RGB(128, 128, 128), // Dark Gray
RGB(255, 0, 0), // Bright Red
RGB( 0, 255, 0), // Bright Green
RGB(255, 255, 0), // Yellow
RGB( 0, 0, 255), // Bright Blue
RGB(255, 0, 255), // Magenta
RGB( 0, 255, 255), // Cyan
RGB(255, 255, 255) // 1 - white
};
/***************************************************************************/
IMG* CreateImg(int cxWidth, int cyHeight, int cPlanes, int cBitCount, int cXPelsPerMeter, int cYPelsPerMeter, BOOL bPalette ) { IMG* pimg = NULL; CTempBitmap bmNew; HBITMAP hbmOld = NULL;
CClientDC dcScreen(NULL);
if (! cPlanes ) { cPlanes = dcScreen.GetDeviceCaps( PLANES ); } if (! cBitCount) { cBitCount = dcScreen.GetDeviceCaps( BITSPIXEL ); }
CDC cDC; cDC.CreateCompatibleDC( &dcScreen ); if (!cDC.m_hDC) { return NULL; }
if (cPlanes * cBitCount > 1) { cDC.SetStretchBltMode(HALFTONE);
}
// Set these to 0 to not create a bitmap
if (cxWidth && cyHeight) { BOOL bMono = (cPlanes == 1 && cBitCount == 1); COLORREF* pcrColors = NULL; int nColors = 0;
cBitCount *= cPlanes; if (cBitCount <= 1) { cBitCount = 1; pcrColors = std2Colors; nColors = 2; } else if (cBitCount <= 4) { cBitCount = 4; pcrColors = std16Colors; nColors = 16; } else if (cBitCount <= 8) { cBitCount = 8; pcrColors = colorColorsDef; nColors = NUM_DEF_COLORS; } else { // I don't want to deal with 15 or 16 bit images
cBitCount = 24; }
HBITMAP hbmNew = NULL;
if (cBitCount == 4) { // Just create a DDB if in 16 colors
hbmNew = CreateCompatibleBitmap( dcScreen.m_hDC, cxWidth, cyHeight); } else { struct BMHDR { BITMAPINFOHEADER bmInfo; RGBQUAD rgb[256]; } DIBHdr = { sizeof(BITMAPINFOHEADER), cxWidth, cyHeight, 1, (WORD)cBitCount, BI_RGB, 0, 0, nColors, nColors, } ;
if (cBitCount <= 8) { RGBQUAD* prgb; COLORREF* pcr; int n;
pcr = pcrColors; prgb = DIBHdr.rgb;
for (n=nColors; n>0; --n, ++pcr, ++prgb) { prgb->rgbRed = GetRValue(*pcr); prgb->rgbGreen = GetGValue(*pcr); prgb->rgbBlue = GetBValue(*pcr); prgb->rgbReserved = 0; } }
LPVOID lpNewBits; hbmNew = CreateDIBSection(cDC.m_hDC, (LPBITMAPINFO)&DIBHdr, DIB_RGB_COLORS, &lpNewBits, NULL, 0); }
if (!hbmNew) { return NULL; } bmNew.Attach(hbmNew); }
TRY { pimg = new IMG; } CATCH (CMemoryException, e) { TRACE( TEXT("CreateImg: Can't alloc an IMG\n") ); return NULL; } END_CATCH
pimg->cxWidth = cxWidth; pimg->cyHeight = cyHeight; pimg->cPlanes = cPlanes; pimg->cBitCount = cBitCount; pimg->cXPelsPerMeter = cXPelsPerMeter; pimg->cYPelsPerMeter = cYPelsPerMeter; pimg->hDC = (HDC)cDC.Detach(); pimg->hBitmap = (HBITMAP)bmNew.Detach(); pimg->hBitmapOld = NULL; pimg->m_pFirstImgWnd = NULL; pimg->bDirty = FALSE; pimg->m_hPalOld = NULL; pimg->m_pPalette = NULL;
pimg->m_bTileGrid = g_bDefaultTileGrid; pimg->m_cxTile = g_defaultTileGridSize.cx; pimg->m_cyTile = g_defaultTileGridSize.cy;
BYTE cRed = GetRValue( crRight ); BYTE cGreen = GetGValue( crRight ); BYTE cBlue = GetBValue( crRight );
if (theApp.m_bPaletted) { crRight = PALETTERGB( cRed, cGreen, cBlue ); } else { crRight = RGB( cRed, cGreen, cBlue ); }
if (pimg->hBitmap) { pimg->hBitmapOld = (HBITMAP)SelectObject(pimg->hDC, pimg->hBitmap); ClearImg( pimg ); }
return(pimg); }
/***************************************************************************/
BOOL ClearImg(IMG* pimg) { #if 1
HBRUSH hNewBrush; HBRUSH hOldBrush = NULL; HPALETTE hpalOld = NULL;
pimg->m_nLastChanged = -1;
if ((hNewBrush = ::CreateSolidBrush( crRight )) == NULL) return FALSE;
if (pimg->m_pPalette) { hpalOld = SelectPalette( pimg->hDC, (HPALETTE)pimg->m_pPalette->m_hObject, FALSE ); RealizePalette( pimg->hDC ); }
hOldBrush = (HBRUSH)SelectObject( pimg->hDC, hNewBrush );
PatBlt( pimg->hDC, 0, 0, pimg->cxWidth, pimg->cyHeight, PATCOPY );
if (hOldBrush) SelectObject(pimg->hDC, hOldBrush);
DeleteObject( hNewBrush );
if (hpalOld) SelectPalette( pimg->hDC, hpalOld, FALSE );
return TRUE; #else
BOOL bResult = FALSE; HBRUSH hNewBrush = ::CreateSolidBrush( crRight );
if ( hNewBrush ) { HBRUSH hOldBrush = (HBRUSH)SelectObject( pimg->hDC, hNewBrush ); if ( hOldBrush ) { HPALETTE hpalOld = SelectPalette( pimg->hDC, (HPALETTE)pimg->m_pPalette->m_hObject, FALSE ); if ( hpalOld ) { RealizePalette( pimg->hDC );
PatBlt( pimg->hDC, 0, 0, pimg->cxWidth, pimg->cyHeight, PATCOPY ); pimg->m_nLastChanged = -1; bResult = TRUE;
SelectPalette( pimg->hDC, hpalOld, FALSE ); } SelectObject(pimg->hDC, hOldBrush); } DeleteObject( hNewBrush ); } return bResult; #endif
}
/***************************************************************************/
void FreeImg(IMG* pimg) { if (! pimg) return;
if (pimg == theImgBrush.m_pImg) theImgBrush.m_pImg = NULL;
if (pimg->hDC) { if (pimg->hBitmapOld) SelectObject( pimg->hDC, pimg->hBitmapOld );
if (pimg->m_hPalOld) SelectPalette( pimg->hDC, pimg->m_hPalOld, FALSE ); // Background ??
DeleteDC(pimg->hDC); }
if (pimg->hBitmap) DeleteObject(pimg->hBitmap);
if (theApp.m_pPalette == pimg->m_pPalette) theApp.m_pPalette = NULL;
if (pimg->m_pPalette) delete pimg->m_pPalette;
if (pimg->m_pBitmapObj->m_pImg == pimg) pimg->m_pBitmapObj->m_pImg = NULL;
if (pImgCur == pimg) pImgCur = NULL;
if (pRubberImg == pimg) pRubberImg = NULL;
delete pimg; }
/***************************************************************************/
void SelectImg(IMG* pimg) { if (pimg == pImgCur) return;
if (theImgBrush.m_pImg) HideBrush();
pImgCur = pimg;
SetupRubber(pimg); }
/***************************************************************************/
void DirtyImg( IMG* pimg ) { CPBDoc* pDoc = (CPBDoc*)((CFrameWnd*)AfxGetMainWnd())->GetActiveDocument();
if (pDoc) { pDoc->SetModifiedFlag( TRUE );
if (theApp.m_bEmbedded) pDoc->NotifyChanged(); }
pimg->bDirty = TRUE; pimg->m_pBitmapObj->SetDirty( TRUE ); }
/***************************************************************************/
void CleanupImages() { FreeImg( pImgCur );
CleanupImgUndo(); CleanupImgRubber(); }
/***************************************************************************/
void InvalImgRect(IMG* pimg, CRect* prc) { CImgWnd* pImgWnd; CImgWnd* pNextImgWnd;
CRect rc;
rc.SetRect(0, 0, pimg->cxWidth, pimg->cyHeight);
if (prc) rc &= *prc;
for (pImgWnd = pimg->m_pFirstImgWnd; pImgWnd; pImgWnd = pNextImgWnd) { CRect rcWnd;
pNextImgWnd = pImgWnd->m_pNextImgWnd;
if (prc) { rcWnd = rc; pImgWnd->ImageToClient(rcWnd);
if (pImgWnd->IsGridVisible()) { rcWnd.right += 1; rcWnd.bottom += 1; } }
pImgWnd->InvalidateRect(prc == NULL ? NULL : &rcWnd, FALSE); } }
/***************************************************************************/
void CommitImgRect(IMG* pimg, CRect* prc) { ASSERT(hRubberDC);
if (hRubberDC == NULL) return;
CRect rc;
if (prc == NULL) { SetRect( &rc, 0, 0, pimg->cxWidth, pimg->cyHeight ); prc = &rc; }
HPALETTE hpalOld = NULL;
if (theApp.m_pPalette && theApp.m_pPalette->m_hObject) { hpalOld = SelectPalette( hRubberDC, (HPALETTE)theApp.m_pPalette->m_hObject, FALSE ); // Background ??
RealizePalette( hRubberDC ); }
BitBlt(hRubberDC, prc->left, prc->top, prc->Width(), prc->Height(), pimg->hDC, prc->left, prc->top, SRCCOPY);
if (hpalOld) SelectPalette( hRubberDC, hpalOld, FALSE ); // Background ??
}
void SelInScreenFirst(CPalette* pPal) { // HACK: Select into screen DC first for GDI bug
CWindowDC hdcScreen(NULL); hdcScreen.SelectPalette(pPal, TRUE); hdcScreen.RealizePalette(); }
BOOL CreateSafePalette(CPalette* pPal, LPLOGPALETTE lpLogPal) { if (!pPal->CreatePalette(lpLogPal)) { return(FALSE); }
SelInScreenFirst(pPal); return(TRUE); }
/***************************************************************************/
BOOL ReplaceImgPalette( IMG* pImg, LPLOGPALETTE lpLogPal ) { if (pImg->m_hPalOld) { ::SelectPalette( pImg->hDC, pImg->m_hPalOld, FALSE ); pImg->m_hPalOld = NULL; }
if (pImg->m_pPalette) delete pImg->m_pPalette;
pImg->m_pPalette = new CPalette;
if (pImg->m_pPalette && CreateSafePalette(pImg->m_pPalette, lpLogPal )) { pImg->m_hPalOld = ::SelectPalette( pImg->hDC, (HPALETTE)pImg->m_pPalette->GetSafeHandle(), FALSE ); ::RealizePalette( pImg->hDC ); InvalImgRect( pImg, NULL ); } else { if (pImg->m_pPalette) delete pImg->m_pPalette;
pImg->m_pPalette = NULL; }
return (pImg->m_pPalette != NULL); }
/***************************************************************************/
void CleanupImgRubber() { if (hRubberDC) { DeleteDC(hRubberDC); hRubberDC = NULL; }
if (hRubberBM) { DeleteObject(hRubberBM); hRubberBM = NULL; }
pRubberImg = NULL;
cxRubberWidth = 0; cyRubberHeight = 0; }
/***************************************************************************/
void IdleImage() { if (g_pMouseImgWnd) { CRect rcImage(0, 0, g_pMouseImgWnd->GetImg()->cxWidth, g_pMouseImgWnd->GetImg()->cyHeight);
g_pMouseImgWnd->ImageToClient( rcImage );
CRect rcClient;
g_pMouseImgWnd->GetClientRect( &rcClient );
rcClient &= rcImage;
CPoint pt; GetCursorPos( &pt );
CPoint ptClient = pt;
g_pMouseImgWnd->ScreenToClient( &ptClient );
if (CWnd::WindowFromPoint( pt ) != g_pMouseImgWnd || ! rcClient.PtInRect( ptClient )) { extern MTI mti;
CImgTool::GetCurrent()->OnLeave( g_pMouseImgWnd, &mti );
g_pMouseImgWnd = NULL;
if (! CImgTool::IsDragging() && ::IsWindow(((CPBFrame*)theApp.m_pMainWnd)->m_statBar.m_hWnd) ) ((CPBFrame*)theApp.m_pMainWnd)->m_statBar.ClearPosition(); } }
if (fDraggingBrush) { CPoint pt; CRect rcClient; CPoint ptClient; CImgWnd* pImgWnd;
GetCursorPos(&pt);
pImgWnd = g_pDragBrushWnd;
if (pImgWnd == NULL) return;
CRect rcImage(0, 0, pImgWnd->GetImg()->cxWidth, pImgWnd->GetImg()->cyHeight);
pImgWnd->ImageToClient( rcImage ); pImgWnd->GetClientRect( &rcClient );
rcClient &= rcImage;
ptClient = pt; pImgWnd->ScreenToClient( &ptClient );
if ( CWnd::WindowFromPoint(pt) != pImgWnd || ! rcClient.PtInRect(ptClient)) { if (fDraggingBrush && theImgBrush.m_pImg == NULL) HideBrush();
pImgWnd->UpdPos( CPoint(-1, -1) ); } else if (GetCapture() == NULL) { CPoint imagePt = ptClient;
pImgWnd->ClientToImage( imagePt );
if (! g_bBrushVisible && fDraggingBrush && CImgTool::GetCurrent()->UsesBrush()) { pImgWnd->ShowBrush( imagePt ); } } } }
/***************************************************************************/
void HideBrush() { if (! g_bBrushVisible) return;
g_bBrushVisible = FALSE;
CImgWnd* pImgWnd = g_pDragBrushWnd;
ASSERT(pImgWnd);
if (pImgWnd == NULL) return;
IMG* pimg = pImgWnd->GetImg();
if (pimg == NULL) return;
HPALETTE hpalOld = pImgWnd->SetImgPalette( hRubberDC, FALSE ); // Background ??
BitBlt( pimg->hDC, rcDragBrush.left, rcDragBrush.top, rcDragBrush.Width(), rcDragBrush.Height(), hRubberDC, rcDragBrush.left, rcDragBrush.top, SRCCOPY );
if (hpalOld) SelectPalette( hRubberDC, hpalOld, FALSE ); // Background ??
InvalImgRect( pimg, &rcDragBrush ); }
/***************************************************************************/
void FixRect(RECT * prc) { int t;
if (prc->left > prc->right) { t = prc->left; prc->left = prc->right; prc->right = t; }
if (prc->top > prc->bottom) { t = prc->top; prc->top = prc->bottom; prc->bottom = t; } }
/***************************************************************************/
BOOL SetupRubber(IMG* pimg) { if (cxRubberWidth < pimg->cxWidth || cyRubberHeight < pimg->cyHeight) { HBITMAP hOldBitmap, hNewBitmap;
HideBrush();
if (hRubberDC == NULL && (hRubberDC = CreateCompatibleDC( pimg->hDC )) == NULL) return FALSE;
hNewBitmap = CreateCompatibleBitmap( pimg->hDC, pimg->cxWidth, pimg->cyHeight );
if (hNewBitmap == NULL) { return FALSE; }
hRubberBM = hNewBitmap;
hOldBitmap = (HBITMAP) SelectObject( hRubberDC, hRubberBM );
if (hOldBitmap) { DeleteObject( hOldBitmap ); }
cxRubberWidth = pimg->cxWidth; cyRubberHeight = pimg->cyHeight; }
if (pRubberImg != pimg) { HideBrush();
HPALETTE hpalOld = NULL;
if (theApp.m_pPalette && theApp.m_pPalette->m_hObject) { hpalOld = SelectPalette( hRubberDC, (HPALETTE)theApp.m_pPalette->m_hObject, FALSE ); RealizePalette( hRubberDC ); }
BitBlt( hRubberDC, 0, 0, pimg->cxWidth, pimg->cyHeight, pimg->hDC, 0, 0, SRCCOPY );
if (hpalOld) SelectPalette( hRubberDC, hpalOld, FALSE ); // Background ??
}
pRubberImg = pimg;
return TRUE; }
/***************************************************************************/
CPalette* CreatePalette( const COLORREF* colors, int nColors ) { CPalette* pPal = new CPalette;
if (pPal) { LPLOGPALETTE pLogPal = (LPLOGPALETTE) LocalAlloc( LMEM_FIXED, sizeof (LOGPALETTE) + sizeof (PALETTEENTRY) * nColors);
if (pLogPal) { pLogPal->palVersion = 0x300; pLogPal->palNumEntries = (WORD)nColors;
for (int i = 0; i < nColors; i++) { pLogPal->palPalEntry[i] = *(PALETTEENTRY*)colors++; pLogPal->palPalEntry[i].peFlags = 0; }
if (! CreateSafePalette(pPal, pLogPal )) { theApp.SetGdiEmergency(); delete pPal; pPal = NULL; }
LocalFree(pLogPal); } else { theApp.SetMemoryEmergency(); delete pPal; pPal = NULL; } } return pPal; }
/***************************************************************************/
CPalette* GetStd16Palette() { return CreatePalette( std16Colors, 16 ); }
/***************************************************************************/
CPalette* GetStd2Palette() { return CreatePalette( std2Colors, 2 ); }
/***************************************************************************/
CPalette* GetStd256Palette() { return CreatePalette( colorColorsDef, NUM_DEF_COLORS ); }
/***************************************************************************/
CPalette *PaletteFromDS(HDC hdc) { DWORD adw[257]; int i,n; CPalette *pPal = new CPalette;
if ( n = GetDIBColorTable(hdc, 0, 256, (LPRGBQUAD)&adw[1]) ) { for (i=1; i<=n; i++) adw[i] = RGB(GetBValue(adw[i]),GetGValue(adw[i]),GetRValue(adw[i]));
adw[0] = MAKELONG(0x300, n);
CreateSafePalette(pPal, (LPLOGPALETTE)&adw[0]); } else { // No Palette in Bitmap! Use default half-tone palette
pPal->Attach(CreateHalftonePalette( NULL )); }
return pPal; }
/////////////////////////////////////////////////////////////////////////////
//
// Packed-DIB Handling Functions
//
// A packed-DIB is a bucket of bits usually consisting of a BITMAPINFOHEADER
// structure followed by an array of RGBQUAD structures followed by the words
// that make up the image. An alternate form consists of a BITMAPCOREHEADER
// structure followed by an array of RGBTRIPLE structures and the image words.
// This format is used by OS/2, but is supported by Windows. The only way
// to tell which format the DIB is using is to check the first word against
// the sizes of the header structures (pretty clever eh?).
//
// This is very similar to a DIB as stored in a file. In fact, a DIB file is
// a BITMAPFILEHEADER structure followed by a packed DIB.
//
// These functions make dealing with packed-DIBs in memory easier.
//
#define WIDTHBYTES(bits) ((((bits) + 31) / 32) * 4)
/***************************************************************************/
void FreeDib(HGLOBAL hDib) { ASSERT( hDib );
if (hDib) GlobalFree(hDib); }
/***************************************************************************/
HGLOBAL DibFromBitmap( HBITMAP hBitmap, DWORD dwStyle, WORD wBits, CPalette* pPal, HBITMAP hMaskBitmap, DWORD& dwLen, LONG cXPelsPerMeter, LONG cYPelsPerMeter ) { ASSERT(hBitmap);
if (hBitmap == NULL) return NULL;
ASSERT(hMaskBitmap == NULL || dwStyle == BI_RGB);
HBITMAP hbm; BITMAP bm; BITMAPINFOHEADER bi; LPBITMAPINFOHEADER lpbi; HDC hDC; DWORD dwSmallLen;
HPALETTE hPal = (HPALETTE)(pPal->GetSafeHandle());
if (theApp.m_bPaletted && ! hPal) hPal = (HPALETTE)::GetStockObject( DEFAULT_PALETTE );
GetObject( hBitmap, sizeof( bm ), (LPSTR)&bm );
if (wBits == 0) wBits = bm.bmPlanes * bm.bmBitsPixel;
if (wBits <= 1) wBits = 1; else if (wBits <= 4) wBits = 4; else if (wBits <= 8) wBits = 8; else wBits = 24;
bi.biSize = sizeof( BITMAPINFOHEADER ); bi.biWidth = bm.bmWidth; bi.biHeight = bm.bmHeight; bi.biPlanes = 1; bi.biBitCount = wBits; bi.biCompression = dwStyle; bi.biSizeImage = 0; // bi.biXPelsPerMeter = theApp.ScreenDeviceInfo.ixPelsPerDM * 10;
// bi.biYPelsPerMeter = theApp.ScreenDeviceInfo.iyPelsPerDM * 10;
// HDC hdc = GetDC(NULL);
// bi.biXPelsPerMeter = MulDiv(::GetDeviceCaps(hdc, LOGPIXELSX),10000, 254);
// bi.biYPelsPerMeter = MulDiv(::GetDeviceCaps(hdc, LOGPIXELSY),10000, 254);
// ReleaseDC (NULL, hdc);
bi.biXPelsPerMeter = cXPelsPerMeter; bi.biYPelsPerMeter = cYPelsPerMeter; bi.biClrUsed = 0; bi.biClrImportant = 0;
dwSmallLen = dwLen = bi.biSize + PaletteSize( (LPSTR) &bi );
lpbi = (LPBITMAPINFOHEADER) GlobalAlloc(GPTR, dwLen);
if (lpbi == NULL) { theApp.SetMemoryEmergency(); return NULL; }
*lpbi = bi;
hbm = CreateBitmap( 2, 2, bm.bmPlanes, bm.bmBitsPixel, NULL ); hDC = CreateCompatibleDC( NULL );
if (hbm == NULL || hDC == NULL) { if (hbm) DeleteObject( hbm );
theApp.SetGdiEmergency(); return NULL; } HPALETTE hPalOld = NULL; HANDLE hbmOld = SelectObject( hDC, hbm );
if (hPal) { hPalOld = SelectPalette( hDC, hPal, FALSE ); RealizePalette( hDC ); }
// Compute the byte size of the DIB...
GetDIBits( hDC, hBitmap, 0, (WORD)bi.biHeight, NULL, (LPBITMAPINFO)lpbi, DIB_RGB_COLORS );
bi = *lpbi;
// If the driver did not fill in the biSizeImage field, make one up
// NOTE: This size will be too big if the bitmap is compressed!
// NOTE: This happens with the Paradise 800x600x256 driver...
if (bi.biSizeImage == 0) { TRACE( TEXT("Display driver bug! We have to compute DIB size...") );
bi.biSizeImage = WIDTHBYTES( (DWORD)bi.biWidth * wBits ) * bi.biHeight;
if (dwStyle != BI_RGB) bi.biSizeImage = (bi.biSizeImage * 3) / 2; }
dwLen = bi.biSize + PaletteSize( (LPSTR)&bi ) + bi.biSizeImage;
if (hMaskBitmap) dwLen += (LONG)WIDTHBYTES( bi.biWidth ) * bi.biHeight;
CHAR* hpv = (CHAR*) GlobalAlloc(GPTR, dwLen);
if (! hpv) { theApp.SetMemoryEmergency();
GlobalFree(lpbi);
if (hbmOld) DeleteObject( SelectObject( hDC, hbmOld ) );
if (hPalOld) SelectPalette( hDC, hPalOld, FALSE );
DeleteDC( hDC );
return NULL; }
memcpy( hpv, (void*)lpbi, dwSmallLen );
GlobalFree(lpbi);
lpbi = (LPBITMAPINFOHEADER)hpv;
LPSTR lpBits = (LPSTR)lpbi + lpbi->biSize + PaletteSize((LPSTR)lpbi); DWORD biSizeImage = lpbi->biSizeImage;
if (hMaskBitmap) { // Do the mask first so the dib ends up with the main bitmap's
// size and palette when we're done...
LONG cbAdjust = ((LONG)WIDTHBYTES( bi.biWidth * wBits )) * bi.biHeight; lpBits += cbAdjust; WORD biBitCount = lpbi->biBitCount; lpbi->biBitCount = 1; lpbi->biSizeImage = 0;
if (GetDIBits( hDC, hMaskBitmap, 0, (WORD)bi.biHeight, lpBits, (LPBITMAPINFO)lpbi, DIB_RGB_COLORS ) == 0) { GlobalFree(hpv);
if (hbmOld) DeleteObject( SelectObject( hDC, hbmOld ) );
if (hPalOld) SelectPalette( hDC, hPalOld, FALSE );
DeleteDC(hDC);
return NULL; }
biSizeImage += lpbi->biSizeImage; lpbi->biBitCount = biBitCount; lpBits -= cbAdjust; }
if (GetDIBits( hDC, hBitmap, 0, (WORD)bi.biHeight, lpBits, (LPBITMAPINFO)lpbi, DIB_RGB_COLORS ) == 0) { GlobalFree(hpv);
if (hbmOld) DeleteObject( SelectObject( hDC, hbmOld ) );
if (hPalOld) SelectPalette( hDC, hPalOld, FALSE );
DeleteDC(hDC);
return NULL; }
lpbi->biSizeImage = biSizeImage;
if (hMaskBitmap) lpbi->biHeight *= 2;
if (hbmOld) DeleteObject( SelectObject( hDC, hbmOld ) );
if (hPalOld) SelectPalette( hDC, hPalOld, FALSE ); DeleteDC( hDC );
return (LPSTR)lpbi; }
/***************************************************************************/
UINT DIBBitsPixel(LPSTR lpbi) { // Calculate the number of colors in the color table based on
// the number of bits per pixel for the DIB.
if (IS_WIN30_DIB(lpbi)) { return(((LPBITMAPINFOHEADER)lpbi)->biBitCount); } else { return(((LPBITMAPCOREHEADER)lpbi)->bcBitCount); } }
WORD DIBNumColors(LPSTR lpbi, BOOL bJustUsed) { WORD wBitCount;
// If this is a Windows style DIB, the number of colors in the
// color table can be less than the number of bits per pixel
// allows for (i.e. lpbi->biClrUsed can be set to some value).
// If this is the case, return the appropriate value.
if (IS_WIN30_DIB( lpbi ) && bJustUsed) { DWORD dwClrUsed = ((LPBITMAPINFOHEADER)lpbi)->biClrUsed;
if (dwClrUsed != 0) return (WORD)dwClrUsed; }
// Calculate the number of colors in the color table based on
// the number of bits per pixel for the DIB.
wBitCount = (WORD)DIBBitsPixel(lpbi);
switch (wBitCount) { case 1: return 2;
case 4: return 16;
case 8: return 256;
default: return 0; } }
/***************************************************************************/
WORD PaletteSize(LPSTR lpbi) {
if (IS_WIN30_DIB(lpbi) && ((LPBITMAPINFOHEADER)lpbi)->biCompression==BI_BITFIELDS) { // Images with bitfields have 3 DWORD's that specify the RGB components
// (respectively) of each pixel.
if (((LPBITMAPINFOHEADER)lpbi)->biSize >= sizeof(BITMAPV4HEADER)) { return 0; } else return(3 * sizeof(DWORD)); }
return DIBNumColors(lpbi,TRUE) * (IS_WIN30_DIB(lpbi) ? sizeof(RGBQUAD) : sizeof(RGBTRIPLE)); }
/***************************************************************************/
LPSTR FindDIBBits(LPSTR lpbi, DWORD dwOffBits) { DWORD dwAfterHdr = *(LPDWORD)lpbi + PaletteSize(lpbi); DWORD dwOff; #if 0
if (dwOffBits && dwAfterHdr != dwOffBits) { MessageBeep(0); } #endif
dwOff = max(dwOffBits, dwAfterHdr); return(lpbi + dwOff); }
/***************************************************************************/
DWORD DIBWidth(LPSTR lpDIB) {
LPBITMAPINFOHEADER lpbmi = (LPBITMAPINFOHEADER)lpDIB; LPBITMAPCOREHEADER lpbmc = (LPBITMAPCOREHEADER)lpDIB;
if (lpbmi->biSize >= sizeof (BITMAPINFOHEADER)) return (DWORD) abs(lpbmi->biWidth); else return (DWORD) abs(lpbmc->bcWidth); }
/***************************************************************************/
DWORD DIBHeight(LPSTR lpDIB) { LPBITMAPINFOHEADER lpbmi = (LPBITMAPINFOHEADER)lpDIB; LPBITMAPCOREHEADER lpbmc = (LPBITMAPCOREHEADER)lpDIB;
if (lpbmi->biSize >= sizeof (BITMAPINFOHEADER)) return (DWORD) abs(lpbmi->biHeight); else return (DWORD) abs(lpbmc->bcHeight); }
/***************************************************************************/
HBITMAP DIBToBitmap( LPSTR lpDIBHdr, CPalette* pPal, HDC hdc ) { ASSERT( lpDIBHdr ); ASSERT( hdc );
if (! lpDIBHdr || ! hdc) return NULL;
LPBYTE lpDIBBits = (LPBYTE)FindDIBBits( lpDIBHdr,0 ); CPalette* ppalOld = NULL; CBitmap* pbmOld = NULL; CBitmap bmTemp; CDC dc;
dc.Attach( hdc );
if (bmTemp.CreateCompatibleBitmap( &dc, 2, 2 )) pbmOld = dc.SelectObject( &bmTemp );
if (pPal) { ASSERT( pPal->m_hObject );
#ifdef FORCEBACKPALETTE
ppalOld = dc.SelectPalette( pPal, TRUE ); #else
ppalOld = dc.SelectPalette( pPal, FALSE ); #endif
dc.RealizePalette(); }
HBITMAP hBitmap = CreateDIBitmap( dc.m_hDC, (LPBITMAPINFOHEADER)lpDIBHdr, CBM_INIT, lpDIBBits, (LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS ); if (ppalOld) dc.SelectPalette( ppalOld, FALSE );
if (pbmOld) dc.SelectObject( pbmOld );
if (bmTemp.m_hObject) bmTemp.DeleteObject();
dc.Detach();
return hBitmap; }
/***************************************************************************/
BOOL ShouldUseDDB(HDC hdc, LPBITMAPINFO lpDIBHdr) { if (!IS_WIN30_DIB(lpDIBHdr)) { // I don't want to write special code to deal with this case
return(FALSE); }
if (lpDIBHdr->bmiHeader.biPlanes*lpDIBHdr->bmiHeader.biBitCount != 4) { // No DDB for mono or 8bit or more
return(FALSE); }
UINT cBitCount = GetDeviceCaps( hdc, BITSPIXEL ) * GetDeviceCaps( hdc, PLANES ); if (cBitCount > 4) { return(FALSE); }
RGBQUAD *lpPal = lpDIBHdr->bmiColors;
for (int i=DIBNumColors((LPSTR)lpDIBHdr, TRUE); i>0; --i, ++lpPal) { COLORREF cr = RGB(lpPal->rgbRed, lpPal->rgbGreen, lpPal->rgbBlue); if (GetNearestColor(hdc, cr) != cr) { return(FALSE); } }
// OK, so this is a WIN30 DIB, the screen is 16 or less colors, it is
// either an uncompressed or RLE DIB, and all the colors in the DIB can
// be shown on the screen. I guess we can use a DDB.
return(TRUE); }
/***************************************************************************/
HBITMAP DIBToDS( LPSTR lpDIB, DWORD dwOffBits, HDC hdc ) { ASSERT( lpDIB ); ASSERT( hdc );
if (! lpDIB || ! hdc) { return NULL; }
LPVOID lpNewBits; LPBITMAPINFO lpDIBHdr = (LPBITMAPINFO)lpDIB; LPBYTE lpDIBBits = (LPBYTE)FindDIBBits( lpDIB, dwOffBits );
{ // New block just to scope dcScreen
CClientDC dcScreen(NULL);
if (ShouldUseDDB(dcScreen.m_hDC, lpDIBHdr)) { return(CreateDIBitmap( dcScreen.m_hDC, &lpDIBHdr->bmiHeader, CBM_INIT, lpDIBBits, lpDIBHdr, DIB_RGB_COLORS )); } }
// Compressed DIB sections are not allowed
DWORD dwCompression = lpDIBHdr->bmiHeader.biCompression; if (IS_WIN30_DIB(lpDIB)) { lpDIBHdr->bmiHeader.biCompression = BI_RGB; } HBITMAP hBitmap = CreateDIBSection( hdc, lpDIBHdr, DIB_RGB_COLORS, &lpNewBits, NULL, 0);
if (IS_WIN30_DIB(lpDIB)) { lpDIBHdr->bmiHeader.biCompression = dwCompression; }
if (hBitmap) { HBITMAP hbmOld = (HBITMAP)SelectObject(hdc, hBitmap); if (hbmOld) { UINT uWid = DIBWidth(lpDIB); UINT uHgt = DIBHeight(lpDIB);
// Fill with white in case the bitmap has any jumps in it.
PatBlt(hdc, 0, 0, uWid, uHgt, WHITENESS);
// StretchDIBits(hdc, 0, 0, uWid, uHgt, 0, 0, uWid, uHgt, lpDIBBits,
// (LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS, SRCCOPY);
SetDIBitsToDevice (hdc,0,0,uWid, uHgt,0,0,0,abs(uHgt),lpDIBBits, (LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS); SelectObject(hdc, hbmOld);
return(hBitmap); }
DeleteObject(hBitmap); }
return(NULL); }
//------------------------------------------------------------------------------
// SetNewPalette - Used solely by GetRainbowPalette below for initialization.
//------------------------------------------------------------------------------
static void SetNewPalette( PALETTEENTRY* const pPal, PWORD pwRainbowColors, UINT R, UINT G, UINT B ) { if (*pwRainbowColors < 256) { WORD wC;
for (wC = 0; wC < *pwRainbowColors; wC++) if (((UINT)GetRValue( *(DWORD*)&pPal[ wC ] ) /* + 1 & ~1 */ ) == (R /* + 1 & ~1 */ ) && ((UINT)GetGValue( *(DWORD*)&pPal[ wC ] ) /* + 1 & ~1 */ ) == (G /* + 1 & ~1 */ ) && ((UINT)GetBValue( *(DWORD*)&pPal[ wC ] ) /* + 1 & ~1 */ ) == (B /* + 1 & ~1 */ )) return;
pPal[*pwRainbowColors].peRed = (BYTE)R; pPal[*pwRainbowColors].peGreen = (BYTE)G; pPal[*pwRainbowColors].peBlue = (BYTE)B; pPal[*pwRainbowColors].peFlags = 0;
(*pwRainbowColors)++; } }
/***************************************************************************/
CPalette* CreateDIBPalette(LPSTR lpbi) { LPLOGPALETTE lpPal; CPalette* pPal = NULL; int iLoop; int wNumColors; LPBITMAPINFO lpbmi; LPBITMAPCOREINFO lpbmc; BOOL bWinStyleDIB; BOOL bGetDriverDefaults = FALSE;
ASSERT( lpbi );
if (lpbi == NULL) return NULL;
lpbmi = (LPBITMAPINFO)lpbi; lpbmc = (LPBITMAPCOREINFO)lpbi; wNumColors = (int)DIBNumColors(lpbi, TRUE); bWinStyleDIB = IS_WIN30_DIB(lpbi);
if (! wNumColors) { if (! theApp.m_bPaletted) return NULL;
bGetDriverDefaults = TRUE; wNumColors = 256; }
lpPal = (LPLOGPALETTE)new CHAR [sizeof( LOGPALETTE ) + sizeof( PALETTEENTRY ) * (wNumColors - 1)];
if (lpPal == NULL) { theApp.SetMemoryEmergency(); return NULL; }
if (bGetDriverDefaults) { #define DIM( X ) (sizeof(X) / sizeof(X[0]))
// GetRainbowPalette - Based on
// Fran Finnegan's column in Microsoft Systems Journal, Sept.-Oct., 1991 (#5).
static BYTE C[] = { 255, 238, 221, 204, 187, 170, 153, 136, 119, 102, 85, 68, 51, 34, 17, 0 }; PALETTEENTRY* pPal = &(lpPal->palPalEntry[0]); WORD wColors = 0; int iC; int iR; int iG; int iB;
for (iC = 0; iC < DIM( C ); iC++) SetNewPalette( pPal, &wColors, C[ iC ], C[ iC ], C[ iC ] ); for (iR = 0; iR < DIM( C ); iR += 3) for (iG = 0; iG < DIM( C ); iG += 3) for (iB = 0; iB < DIM( C ); iB += 3) SetNewPalette( pPal, &wColors, C[ iR ], C[ iG ], C[ iB ] ); for (iC = 0; iC < DIM( C ); iC++) { SetNewPalette( pPal, &wColors, C[ iC ], 0, 0 ); SetNewPalette( pPal, &wColors, 0, C[ iC ], 0 ); SetNewPalette( pPal, &wColors, 0, 0, C[ iC ] ); } } else for (iLoop = 0; iLoop < wNumColors; iLoop++) { if (bWinStyleDIB) { lpPal->palPalEntry[iLoop].peRed = lpbmi->bmiColors[iLoop].rgbRed; lpPal->palPalEntry[iLoop].peGreen = lpbmi->bmiColors[iLoop].rgbGreen; lpPal->palPalEntry[iLoop].peBlue = lpbmi->bmiColors[iLoop].rgbBlue; lpPal->palPalEntry[iLoop].peFlags = 0; } else { lpPal->palPalEntry[iLoop].peRed = lpbmc->bmciColors[iLoop].rgbtRed; lpPal->palPalEntry[iLoop].peGreen = lpbmc->bmciColors[iLoop].rgbtGreen; lpPal->palPalEntry[iLoop].peBlue = lpbmc->bmciColors[iLoop].rgbtBlue; lpPal->palPalEntry[iLoop].peFlags = 0; } } lpPal->palVersion = 0x300; lpPal->palNumEntries = (WORD)wNumColors;
pPal = new CPalette;
if (pPal == NULL || ! CreateSafePalette(pPal, lpPal )) { if (pPal) delete pPal; pPal = NULL; }
delete [] (CHAR*)lpPal;
return pPal; }
/***************************************************************************/
void Draw3dRect(HDC hDC, RECT * prc) { CDC* pDC = CDC::FromHandle(hDC); CBrush* pOldBrush = pDC->SelectObject( GetSysBrush( COLOR_BTNSHADOW ) );
pDC->PatBlt(prc->left, prc->top, prc->right - prc->left - 1, 1, PATCOPY); pDC->PatBlt(prc->left, prc->top + 1, 1, prc->bottom - prc->top - 2, PATCOPY);
pDC->SelectObject(GetSysBrush( COLOR_BTNHIGHLIGHT ));
pDC->PatBlt(prc->left + 1, prc->bottom - 1, prc->right - prc->left - 1, 1, PATCOPY); pDC->PatBlt(prc->right - 1, prc->top + 1, 1, prc->bottom - prc->top - 1, PATCOPY);
pDC->SelectObject(pOldBrush); }
/***************************************************************************/ // DrawBitmap:
// See header file for usage.
void DrawBitmap(CDC* dc, CBitmap* bmSrc, CRect* rc, DWORD dwROP /* = SRCCOPY */, CDC* memdc /* = NULL */) { CBitmap* obm; CDC* odc = (memdc? memdc : (new CDC));
if (!memdc) odc->CreateCompatibleDC(dc);
obm = odc->SelectObject(bmSrc);
BITMAP bms; bmSrc->GetObject(sizeof (BITMAP), (LPSTR)(LPBITMAP)(&bms));
if (rc) { dc->BitBlt(rc->left + ((rc->right - rc->left - bms.bmWidth) >> 1), rc->top + ((rc->bottom - rc->top - bms.bmHeight) >> 1), bms.bmWidth, bms.bmHeight, odc, 0, 0, dwROP); } else { dc->BitBlt(0, 0, bms.bmWidth, bms.bmHeight, odc, 0, 0, dwROP); }
odc->SelectObject(obm); if (!memdc) { odc->DeleteDC(); delete odc; } }
/***************************************************************************/
BOOL EnsureUndoSize(IMG* pimg) { if (cxUndoWidth < pimg->cxWidth || cyUndoHeight < pimg->cyHeight || (int)cUndoPlanes != pimg->cPlanes || (int)cUndoBitCount != pimg->cBitCount) { HBITMAP hNewUndoImgBitmap = NULL; // HBITMAP hNewUndoMaskBitmap = NULL;
HPALETTE hNewUndoPalette = NULL;
hNewUndoImgBitmap = CreateCompatibleBitmap( pimg->hDC, pimg->cxWidth, pimg->cyHeight );
if (hNewUndoImgBitmap == NULL) { TRACE(TEXT("EnsureUndoSize: Create image bitmap failed!\n")); return FALSE; }
// hNewUndoMaskBitmap = CreateBitmap( pimg->cxWidth, pimg->cyHeight, 1, 1, NULL );
// if (hNewUndoMaskBitmap == NULL)
// {
// TRACE(TEXT("EnsureUndoSize: Create mask bitmap failed!\n"));
// DeleteObject( hNewUndoImgBitmap );
// return FALSE;
// }
// if (theApp.m_pPalette)
// {
// LOGPALETTE256 logPal;
// logPal.palVersion = 0x300;
// logPal.palNumEntries = theApp.m_pPalette->GetPaletteEntries( 0, 256,
// &logPal.palPalEntry[0] );
// theApp.m_pPalette->GetPaletteEntries( 0, logPal.palNumEntries,
// &logPal.palPalEntry[0] );
// hNewUndoPalette = ::CreatePalette( (LPLOGPALETTE)&logPal );
// if (! hNewUndoPalette)
// {
// TRACE("EnsureUndoSize: Create palette bitmap failed!\n");
// DeleteObject( hNewUndoImgBitmap );
// DeleteObject( hNewUndoMaskBitmap );
// return FALSE;
// }
// }
if (g_hUndoImgBitmap) DeleteObject(g_hUndoImgBitmap);
// if (g_hUndoPalette)
// DeleteObject(g_hUndoPalette);
g_hUndoImgBitmap = hNewUndoImgBitmap; // g_hUndoPalette = hNewUndoPalette;
cxUndoWidth = pimg->cxWidth; cyUndoHeight = pimg->cyHeight; cUndoPlanes = (BYTE)pimg->cPlanes; cUndoBitCount = (BYTE)pimg->cBitCount; }
return TRUE; }
/***************************************************************************/
void CleanupImgUndo() { if (g_hUndoImgBitmap) DeleteObject(g_hUndoImgBitmap);
if (g_hUndoPalette) DeleteObject(g_hUndoPalette);
g_hUndoImgBitmap = NULL; g_hUndoPalette = NULL; cxUndoWidth = 0; cyUndoHeight = 0; cUndoPlanes = 0; cUndoBitCount = 0; }
/***************************************************************************/
BOOL SetUndo(IMG* pimg) { BOOL bSuccess = FALSE; HDC hTempDC = NULL; HBITMAP hOldBitmap = NULL; CRect rect;
if (! EnsureUndoSize( pimg )) goto LReturn;
rect.SetRect( 0, 0, pimg->cxWidth, pimg->cyHeight );
hTempDC = CreateCompatibleDC( pimg->hDC );
if (hTempDC == NULL) { TRACE( TEXT("SetUndo: CreateCompatibleDC failed\n") ); goto LReturn; }
hOldBitmap = (HBITMAP)SelectObject( hTempDC, g_hUndoImgBitmap );
BitBlt( hTempDC, 0, 0, rect.Width(), rect.Height(), pimg->hDC, rect.left, rect.top, SRCCOPY );
SelectObject( hTempDC, hOldBitmap ); DeleteDC( hTempDC );
bSuccess = TRUE;
LReturn:
return bSuccess; }
/***************************************************************************/
void DrawBrush(IMG* pimg, CPoint pt, BOOL bDraw) { int nStrokeWidth = CImgTool::GetCurrent()->GetStrokeWidth();
if (g_bCustomBrush) { CRect rc(pt.x, pt.y, pt.x + theImgBrush.m_size.cx, pt.y + theImgBrush.m_size.cy); rc -= (CPoint)theImgBrush.m_handle;
theImgBrush.m_rcSelection = rc;
int nCombineMode; COLORREF cr;
if (bDraw) { nCombineMode = (theImgBrush.m_bOpaque) ? combineReplace : combineMatte; cr = crLeft; } else { nCombineMode = combineColor; cr = crRight; }
if (CImgTool::GetCurrentID() == IDMX_TEXTTOOL) { // extern CTextTool g_textTool;
// g_textTool.Render(CDC::FromHandle(pimg->hDC), rc, TRUE, TRUE);
} else { switch (nCombineMode) { #ifdef DEBUG
default: ASSERT(FALSE); #endif
case combineColor: theImgBrush.BltColor(pimg, rc.TopLeft(), cr); break;
case combineMatte: theImgBrush.BltMatte(pimg, rc.TopLeft()); break;
case combineReplace: theImgBrush.BltReplace(pimg, rc.TopLeft()); break; } }
InvalImgRect (pimg, &rc); CommitImgRect(pimg, &rc); } else { DrawImgLine(pimg, pt, pt, bDraw ? crLeft : crRight, CImgTool::GetCurrent()->GetStrokeWidth(), CImgTool::GetCurrent()->GetStrokeShape(), TRUE); rcDragBrush.left = pt.x - nStrokeWidth / 2; rcDragBrush.top = pt.y - nStrokeWidth / 2; rcDragBrush.right = rcDragBrush.left + nStrokeWidth; rcDragBrush.bottom = rcDragBrush.top + nStrokeWidth; } }
/***************************************************************************/
void DrawDCLine(HDC hDC, CPoint pt1, CPoint pt2, COLORREF color, int nWidth, int nShape, CRect& rc) { HPEN hOldPen; HBRUSH hBrush; HBRUSH hOldBrush; int sx; int sy; int ex; int ey; int nWidthD2 = nWidth / 2;
sx = pt1.x; sy = pt1.y; ex = pt2.x; ey = pt2.y;
if (hDC) { hBrush = ::CreateSolidBrush( color ); hOldBrush = (HBRUSH)SelectObject( hDC, hBrush );
if (nWidth == 1) { HPEN hPen = CreatePen(PS_SOLID, 1, (COLORREF)color);
if (hPen) { hOldPen = (HPEN)SelectObject(hDC, hPen);
::MoveToEx(hDC, sx, sy, NULL); LineTo(hDC, ex, ey); SetPixel(hDC, ex, ey, color); SelectObject(hDC, hOldPen); DeleteObject(hPen); } } else { // hOldPen = (HPEN)SelectObject(hDC, GetStockObject( NULL_PEN ));
BrushLine( CDC::FromHandle(hDC), CPoint(sx - nWidthD2, sy - nWidthD2), CPoint(ex - nWidthD2, ey - nWidthD2), nWidth, nShape); // SelectObject( hDC, hOldPen );
}
SelectObject(hDC, hOldBrush); DeleteObject(hBrush); }
if (sx < ex) { rc.left = sx; rc.right = ex + 1; } else { rc.left = ex; rc.right = sx + 1; }
if (sy < ey) { rc.top = sy; rc.bottom = ey + 1; } else { rc.top = ey; rc.bottom = sy + 1; }
rc.left -= nWidth * 2; rc.top -= nWidth * 2; rc.right += nWidth * 2; rc.bottom += nWidth * 2; }
void DrawImgLine(IMG* pimg, CPoint pt1, CPoint pt2, COLORREF color, int nWidth, int nShape, BOOL bCommit) { CRect rc;
DrawDCLine(pimg->hDC, pt1, pt2, color, nWidth, nShape, rc);
InvalImgRect(pimg, &rc);
if (bCommit) { CommitImgRect(pimg, &rc); } }
/***************************************************************************/
void FillImgRect( HDC hDC, CRect* prc, COLORREF cr ) { FixRect( prc );
CPoint pt1 = prc->TopLeft(); CPoint pt2 = prc->BottomRight();
StandardiseCoords( &pt1, &pt2 );
int sx = pt1.x; int sy = pt1.y; int ex = pt2.x; int ey = pt2.y;
CRect rc( sx, sy, ex, ey );
HBRUSH hBr = ::CreateSolidBrush( cr );
if (! hBr) { theApp.SetGdiEmergency(); return; }
if (CImgTool::GetCurrentID() == IDMB_PICKRGNTOOL) { if (theImgBrush.m_cRgnPolyFreeHandSel.GetSafeHandle()) { // offset bitmap in the imgwnd from selection boundary
theImgBrush.m_cRgnPolyFreeHandSel.OffsetRgn( rc.left, rc.top );
::FillRgn( hDC, (HRGN)theImgBrush.m_cRgnPolyFreeHandSel.m_hObject, hBr ); // offset back to selection boundary
theImgBrush.m_cRgnPolyFreeHandSel.OffsetRgn( -rc.left, -rc.top ); } } else {
HPEN hPen = CreatePen( PS_NULL, 0, 0 );
if (hPen) { HPEN hOldPen = (HPEN)SelectObject( hDC, hPen ); HBRUSH hOldBr = (HBRUSH)SelectObject( hDC, hBr );
Rectangle( hDC, sx, sy, ex, ey );
SelectObject( hDC, hOldPen); DeleteObject( hPen ); SelectObject( hDC, hOldBr ); } }
DeleteObject( hBr );
*prc = rc; }
/***************************************************************************/
void BrushLine(CDC* pDC, CPoint fromPt, CPoint toPt, int nWidth, int nShape) { CPen* pOldPen = (CPen*) pDC->SelectStockObject(NULL_PEN); CSize brushSize(nWidth, nWidth);
int octant;
if (nShape == slantedRightBrush || nShape == slantedLeftBrush) { int dx = abs(toPt.x - fromPt.x); int dy = abs(toPt.y - fromPt.y);
if (toPt.x > fromPt.x) { if (toPt.y < fromPt.y) octant = (dx > dy) ? 0 : 1; else octant = (dx > dy) ? 7 : 6; } else { if (toPt.y < fromPt.y) octant = (dx > dy) ? 3 : 2; else octant = (dx > dy) ? 4 : 5; } }
switch (nShape) { case squareBrush: PolyTo(pDC, fromPt, toPt, brushSize); break;
case roundBrush: if (toPt != fromPt) { CRect tan; CPoint polyPts [4];
if (!GetTanPt(brushSize, (CPoint)(toPt - fromPt), tan)) return;
polyPts[0].x = fromPt.x + tan.left; polyPts[1].x = fromPt.x + tan.right; polyPts[2].x = toPt.x + tan.right; polyPts[3].x = toPt.x + tan.left;
polyPts[0].y = fromPt.y + tan.top; polyPts[1].y = fromPt.y + tan.bottom; polyPts[2].y = toPt.y + tan.bottom; polyPts[3].y = toPt.y + tan.top;
pDC->Polygon(polyPts, 4);
Mylipse(pDC->m_hDC, fromPt.x, fromPt.y, fromPt.x + brushSize.cx, fromPt.y + brushSize.cy, TRUE); }
Mylipse(pDC->m_hDC, toPt.x, toPt.y, toPt.x + brushSize.cx, toPt.y + brushSize.cy, TRUE); break;
case slantedLeftBrush: { CPoint polyPts [6];
fromPt.x -= 1; toPt.x -= 1;
switch (octant) { case 0: polyPts[0].x = fromPt.x; polyPts[1].x = fromPt.x + 1; polyPts[2].x = toPt.x + 1; polyPts[3].x = toPt.x + brushSize.cy + 1; polyPts[4].x = toPt.x + brushSize.cy; polyPts[5].x = fromPt.x + brushSize.cy; polyPts[0].y = polyPts[1].y = fromPt.y + brushSize.cy; polyPts[2].y = toPt.y + brushSize.cy; polyPts[3].y = polyPts[4].y = toPt.y; polyPts[5].y = fromPt.y; break;
case 1: polyPts[0].x = fromPt.x; polyPts[1].x = fromPt.x + 1; polyPts[2].x = fromPt.x + brushSize.cy + 1; polyPts[3].x = toPt.x + brushSize.cy + 1; polyPts[4].x = toPt.x + brushSize.cy; polyPts[5].x = toPt.x; polyPts[0].y = polyPts[1].y = fromPt.y + brushSize.cy; polyPts[2].y = fromPt.y; polyPts[3].y = polyPts[4].y = toPt.y; polyPts[5].y = toPt.y + brushSize.cy; break;
case 2: case 3: polyPts[0].x = fromPt.x + 1; polyPts[1].x = fromPt.x; polyPts[2].x = toPt.x; polyPts[3].x = toPt.x + brushSize.cy; polyPts[4].x = toPt.x + brushSize.cy + 1; polyPts[5].x = fromPt.x + brushSize.cy + 1; polyPts[0].y = polyPts[1].y = fromPt.y + brushSize.cy; polyPts[2].y = toPt.y + brushSize.cy; polyPts[3].y = polyPts[4].y = toPt.y; polyPts[5].y = fromPt.y; break;
case 4: polyPts[0].x = fromPt.x + brushSize.cy + 1; polyPts[1].x = fromPt.x + brushSize.cy; polyPts[2].x = toPt.x + brushSize.cy; polyPts[3].x = toPt.x; polyPts[4].x = toPt.x + 1; polyPts[5].x = fromPt.x + 1; polyPts[0].y = polyPts[1].y = fromPt.y; polyPts[2].y = toPt.y; polyPts[3].y = polyPts[4].y = toPt.y + brushSize.cy; polyPts[5].y = fromPt.y + brushSize.cy; break;
case 5: polyPts[0].x = fromPt.x + brushSize.cy + 1; polyPts[1].x = fromPt.x + brushSize.cy; polyPts[2].x = fromPt.x; polyPts[3].x = toPt.x; polyPts[4].x = toPt.x + 1; polyPts[5].x = toPt.x + brushSize.cy + 1; polyPts[0].y = polyPts[1].y = fromPt.y; polyPts[2].y = fromPt.y + brushSize.cy; polyPts[3].y = polyPts[4].y = toPt.y + brushSize.cy; polyPts[5].y = toPt.y; break;
default: polyPts[0].x = fromPt.x + brushSize.cy; polyPts[1].x = fromPt.x + brushSize.cy + 1; polyPts[2].x = toPt.x + brushSize.cy + 1; polyPts[3].x = toPt.x + 1; polyPts[4].x = toPt.x; polyPts[5].x = fromPt.x; polyPts[0].y = polyPts[1].y = fromPt.y; polyPts[2].y = toPt.y; polyPts[3].y = polyPts[4].y = toPt.y + brushSize.cy; polyPts[5].y = fromPt.y + brushSize.cy; break; }
pDC->Polygon(polyPts, 6); } break;
case slantedRightBrush: { CPoint polyPts [6];
switch (octant) { case 0: case 1: polyPts[0].x = fromPt.x + brushSize.cy; polyPts[1].x = fromPt.x + brushSize.cy + 1; polyPts[2].x = toPt.x + brushSize.cy + 1; polyPts[3].x = toPt.x + 1; polyPts[4].x = toPt.x; polyPts[5].x = fromPt.x; polyPts[0].y = polyPts[1].y = fromPt.y + brushSize.cy; polyPts[2].y = toPt.y + brushSize.cy; polyPts[3].y = polyPts[4].y = toPt.y; polyPts[5].y = fromPt.y; break;
case 2 : polyPts[0].x = fromPt.x + brushSize.cy + 1; polyPts[1].x = fromPt.x + brushSize.cy; polyPts[2].x = fromPt.x; polyPts[3].x = toPt.x; polyPts[4].x = toPt.x + 1; polyPts[5].x = toPt.x + brushSize.cy + 1; polyPts[0].y = polyPts[1].y = fromPt.y + brushSize.cy; polyPts[2].y = fromPt.y; polyPts[3].y = polyPts[4].y = toPt.y; polyPts[5].y = toPt.y + brushSize.cy; break;
case 3 : polyPts[0].x = fromPt.x + brushSize.cy + 1; polyPts[1].x = fromPt.x + brushSize.cy; polyPts[2].x = toPt.x + brushSize.cy; polyPts[3].x = toPt.x; polyPts[4].x = toPt.x + 1; polyPts[5].x = fromPt.x + 1; polyPts[0].y = polyPts[1].y = fromPt.y + brushSize.cy; polyPts[2].y = toPt.y + brushSize.cy; polyPts[3].y = polyPts[4].y = toPt.y; polyPts[5].y = fromPt.y; break;
case 4 : case 5 : polyPts[0].x = fromPt.x + 1; polyPts[1].x = fromPt.x; polyPts[2].x = toPt.x; polyPts[3].x = toPt.x + brushSize.cy; polyPts[4].x = toPt.x + brushSize.cy + 1; polyPts[5].x = fromPt.x + brushSize.cy + 1; polyPts[0].y = polyPts[1].y = fromPt.y; polyPts[2].y = toPt.y; polyPts[3].y = polyPts[4].y = toPt.y + brushSize.cy; polyPts[5].y = fromPt.y + brushSize.cy; break;
case 6 : polyPts[0].x = fromPt.x; polyPts[1].x = fromPt.x + 1; polyPts[2].x = fromPt.x + brushSize.cy + 1; polyPts[3].x = toPt.x + brushSize.cy + 1; polyPts[4].x = toPt.x + brushSize.cy; polyPts[5].x = toPt.x; polyPts[0].y = polyPts[1].y = fromPt.y; polyPts[2].y = fromPt.y + brushSize.cy; polyPts[3].y = polyPts[4].y = toPt.y + brushSize.cy; polyPts[5].y = toPt.y; break;
default : polyPts[0].x = fromPt.x; polyPts[1].x = fromPt.x + 1; polyPts[2].x = toPt.x + 1; polyPts[3].x = toPt.x + brushSize.cy + 1; polyPts[4].x = toPt.x + brushSize.cy; polyPts[5].x = fromPt.x + brushSize.cy; polyPts[0].y = polyPts[1].y = fromPt.y; polyPts[2].y = toPt.y; polyPts[3].y = polyPts[4].y = toPt.y + brushSize.cy; polyPts[5].y = fromPt.y + brushSize.cy; break; }
pDC->Polygon(polyPts, 6); } break; }
pDC->SelectObject(pOldPen); }
/***************************************************************************/
void SetCombineMode(int wNewCombineMode) { wCombineMode = wNewCombineMode; }
/***************************************************************************/
static int cxLastShape; static int cyLastShape; static int cxShapeBitmap; static int cyShapeBitmap; static CBitmap shapeBitmap; static enum { ellipse, roundRect } nLastShape;
void Mylipse(HDC hDC, int x1, int y1, int x2, int y2, BOOL bFilled) { COLORREF crNewBk, crNewText; GetMonoBltColors(hDC, NULL, crNewBk, crNewText);
COLORREF crOldText = SetTextColor(hDC, crNewText); COLORREF crOldBk = SetBkColor (hDC, crNewBk);
int cx = x2 - x1; int cy = y2 - y1;
if (!bFilled) { Ellipse(hDC, x1, y1, x2, y2); } else if (cx == cy && cx > 0 && cx <= 8) { // HACK: The Windows Ellipse function is no good for small ellipses, so I
// use some little bitmaps here for filled circles 1 to 8 pixels in
// diameter.
static CBitmap g_ellipses [8];
if (g_ellipses[cx - 1].m_hObject == NULL && ! g_ellipses[cx - 1].LoadBitmap(IDB_ELLIPSE1 + cx - 1)) { theApp.SetMemoryEmergency(); SetTextColor(hDC, crOldText); SetBkColor(hDC, crOldBk); return; }
HDC hTempDC = CreateCompatibleDC(hDC); if (hTempDC == NULL) { theApp.SetGdiEmergency(); SetTextColor(hDC, crOldText); SetBkColor(hDC, crOldBk); return; }
HBITMAP hOldBitmap = (HBITMAP) SelectObject(hTempDC, g_ellipses[cx - 1].m_hObject); BitBlt(hDC, x1, y1, cx, cy, hTempDC, 0, 0, DSPDxax); SelectObject(hTempDC, hOldBitmap); DeleteDC(hTempDC); } else if (cx > 0 && cy > 0) { // Actually, Ellipse() is just no good... Let's do as much
// as possible our selves to fix it! Here we draw the ellipse
// into a monochrome bitmap to get the shape and then use that
// as a mask to get the current pattern into the imge.
HDC hTempDC = CreateCompatibleDC(hDC); if (hTempDC == NULL) { theApp.SetGdiEmergency(); SetTextColor(hDC, crOldText); SetBkColor(hDC, crOldBk); return; }
BOOL bRefill = FALSE;
if (cx > cxShapeBitmap || cy > cyShapeBitmap) { shapeBitmap.DeleteObject(); if (shapeBitmap.CreateBitmap(cx, cy, 1, 1, NULL)) { cxShapeBitmap = cx; cyShapeBitmap = cy; bRefill = TRUE; } }
if (shapeBitmap.m_hObject == NULL) { theApp.SetMemoryEmergency(); DeleteDC(hTempDC); SetTextColor(hDC, crOldText); SetBkColor(hDC, crOldBk); return; }
if (cx != cxLastShape || cy != cyLastShape || nLastShape != ellipse) { cxLastShape = cx; cyLastShape = cy; nLastShape = ellipse; bRefill = TRUE; }
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hTempDC, shapeBitmap.m_hObject);
if (bRefill) { PatBlt(hTempDC, 0, 0, cx, cy, BLACKNESS); SelectObject(hTempDC, GetStockObject(WHITE_BRUSH)); SelectObject(hTempDC, GetStockObject(WHITE_PEN)); Ellipse(hTempDC, 0, 0, cx, cy); }
BitBlt(hDC, x1, y1, cx, cy, hTempDC, 0, 0, DSPDxax);
SelectObject(hTempDC, hOldBitmap); DeleteDC(hTempDC); }
SetTextColor(hDC, crOldText); SetBkColor(hDC, crOldBk); }
/***************************************************************************/ #ifdef XYZZYZ
void MyRoundRect(HDC hDC, int x1, int y1, int x2, int y2, int nEllipseWidth, int nEllipseHeight, BOOL bFilled) { int cx = x2 - x1; int cy = y2 - y1;
if (!bFilled) { RoundRect(hDC, x1, y1, x2, y2, nEllipseWidth, nEllipseHeight); return; }
if (cx > 0 && cy > 0) { HDC hTempDC = CreateCompatibleDC(hDC);
if (hTempDC == NULL) { theApp.SetGdiEmergency(); return; }
BOOL bRefill = FALSE;
if (cx > cxShapeBitmap || cy > cyShapeBitmap) { shapeBitmap.DeleteObject(); if (shapeBitmap.CreateBitmap(cx, cy, 1, 1, NULL)) { cxShapeBitmap = cx; cyShapeBitmap = cy; bRefill = TRUE; } }
if (shapeBitmap.m_hObject == NULL) { theApp.SetMemoryEmergency(); DeleteDC(hTempDC); return; }
if (cx != cxLastShape || cy != cyLastShape || nLastShape != roundRect) { cxLastShape = cx; cyLastShape = cy; nLastShape = roundRect; bRefill = TRUE; }
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hTempDC, shapeBitmap.m_hObject);
if (bRefill) { PatBlt(hTempDC, 0, 0, cx, cy, BLACKNESS); SelectObject(hTempDC, GetStockObject(WHITE_BRUSH)); SelectObject(hTempDC, GetStockObject(WHITE_PEN)); RoundRect(hTempDC, 0, 0, cx, cy, nEllipseWidth, nEllipseHeight); }
BitBlt(hDC, x1, y1, cx, cy, hTempDC, 0, 0, DSna); BitBlt(hDC, x1, y1, cx, cy, hTempDC, 0, 0, DSPao);
SelectObject(hTempDC, hOldBitmap); DeleteDC(hTempDC); } } #endif
/***************************************************************************/
void PolyTo(CDC* pDC, CPoint fromPt, CPoint toPt, CSize size) { CPoint polyPts [6];
if (toPt.x > fromPt.x) { polyPts[0].x = polyPts[1].x = fromPt.x; polyPts[2].x = toPt.x; polyPts[3].x = polyPts[4].x = toPt.x + size.cx; polyPts[5].x = fromPt.x + size.cx; } else { polyPts[0].x = polyPts[1].x = fromPt.x + size.cx; polyPts[2].x = toPt.x + size.cx; polyPts[3].x = polyPts[4].x = toPt.x; polyPts[5].x = fromPt.x; }
if (toPt.y > fromPt.y) { polyPts[0].y = polyPts[5].y = fromPt.y; polyPts[1].y = fromPt.y + size.cy; polyPts[2].y = polyPts[3].y = toPt.y + size.cy; polyPts[4].y = toPt.y; } else { polyPts[0].y = polyPts[5].y = fromPt.y + size.cy; polyPts[1].y = fromPt.y; polyPts[2].y = polyPts[3].y = toPt.y; polyPts[4].y = toPt.y + size.cy; }
if (pDC) pDC->Polygon(polyPts, 6); }
/***************************************************************************/
BOOL GetTanPt(CSize size, CPoint delta, CRect& tan) { int x, y; int xExt, yExt, theExt, xTemp; CDC dc; CBitmap* pOldBitmap, bitmap;
size.cx += 1; size.cy += 1;
tan.SetRect(0, 0, 0, 0);
if (!dc.CreateCompatibleDC(NULL)) { theApp.SetGdiEmergency(); return FALSE; }
if (!bitmap.CreateCompatibleBitmap(&dc, size.cx, size.cy)) { theApp.SetMemoryEmergency(); return FALSE; }
VERIFY((pOldBitmap = dc.SelectObject(&bitmap)));
TRY { CBrush cBrushWhite(PALETTERGB(0xff, 0xff, 0xff)); CRect cRectTmp(0,0,size.cx, size.cy); dc.FillRect(&cRectTmp, &cBrushWhite); // dc.PatBlt(0, 0, size.cx, size.cy, WHITENESS);
} CATCH(CResourceException, e) { } END_CATCH dc.SelectStockObject(NULL_PEN); dc.SelectStockObject(BLACK_BRUSH); Mylipse(dc.m_hDC, 0, 0, size.cx, size.cy, TRUE);
yExt = 0; for (xExt = 0; xExt < size.cx - 1; xExt++) { if (dc.GetPixel(xExt, 0) == 0) break; } theExt = 10 * xExt;
if (delta.y == 0) { tan.SetRect(xExt, 0, xExt, size.cy - 1); } else { for (y = 0; y < size.cy; y++) { for (x = 0; x < size.cx - 1; x++) { if (dc.GetPixel(x, y) == 0) break; }
xTemp = 10 * x - 10 * y * delta.x / delta.y; if (theExt > xTemp) { xExt = x; yExt = y; theExt = xTemp; } else if (theExt < xTemp) { break; } }
tan.left = xExt; tan.top = yExt;
for (y = 0; y < size.cy; y++) { for (x = size.cx - 1; x > 0; x--) { if (dc.GetPixel(x, y) == 0) break; } xTemp = 10 * x - 10 * y * delta.x / delta.y; if (theExt < xTemp) { xExt = x; yExt = y; theExt = xTemp; } else if (theExt > xTemp) { break; } }
tan.right = xExt; tan.bottom = yExt; }
dc.SelectObject(pOldBitmap);
return TRUE; }
/***************************************************************************/
void PickupSelection() { // Time to pick up the bits!
ASSERT(theImgBrush.m_pImg);
if (theImgBrush.m_pImg == NULL) return;
CPalette* ppalOld = theImgBrush.SetBrushPalette( &theImgBrush.m_dc, FALSE ); // Background ??
CDC* pImgDC = CDC::FromHandle( theImgBrush.m_pImg->hDC );
if (CImgTool::GetCurrentID() == IDMB_PICKRGNTOOL) { TRY { CBrush cBrushBk( crRight ); CRect cRectTmp( 0, 0, theImgBrush.m_size.cx, theImgBrush.m_size.cy );
theImgBrush.m_dc.FillRect( &cRectTmp, &cBrushBk ); } CATCH(CResourceException, e) { theApp.SetGdiEmergency(); return; } END_CATCH
if (theImgBrush.m_cRgnPolyFreeHandSel.GetSafeHandle()) { theImgBrush.m_dc.SelectClipRgn(&theImgBrush.m_cRgnPolyFreeHandSel);
theImgBrush.m_dc.StretchBlt( 0, 0, theImgBrush.m_size.cx, theImgBrush.m_size.cy, pImgDC, theImgBrush.m_rcSelection.left, theImgBrush.m_rcSelection.top, theImgBrush.m_rcSelection.Width(), theImgBrush.m_rcSelection.Height(), SRCCOPY );
theImgBrush.m_dc.SelectClipRgn(NULL); } } else { theImgBrush.m_dc.BitBlt( 0, 0, theImgBrush.m_size.cx, theImgBrush.m_size.cy, pImgDC, theImgBrush.m_rcSelection.left, theImgBrush.m_rcSelection.top, SRCCOPY ); }
if (ppalOld) theImgBrush.m_dc.SelectPalette( ppalOld, FALSE );
theImgBrush.RecalcMask( crRight ); }
/***************************************************************************/
void CommitSelection(BOOL bSetUndo) { if (theImgBrush.m_bMakingSelection) return;
if (! theImgBrush.m_bSmearSel && ( theImgBrush.m_pImg == NULL || theImgBrush.m_bFirstDrag || theImgBrush.m_bLastDragWasASmear)) { return; }
if (theImgBrush.m_bLastDragWasFirst && (theImgBrush.m_bMoveSel || theImgBrush.m_bSmearSel)) { return; }
TRACE1( "CommitSelection(%d)\n", bSetUndo );
if (bSetUndo) { HideBrush(); CRect rectUndo = theImgBrush.m_rcSelection;
if (theImgBrush.m_bLastDragWasFirst) { theImgBrush.m_bLastDragWasFirst = FALSE; rectUndo |= theImgBrush.m_rcDraggedFrom; } else { SetUndo(theImgBrush.m_pImg); }
CImgWnd::c_pImgWndCur->FinishUndo(rectUndo); }
if (CImgTool::GetCurrentID() != IDMX_TEXTTOOL) { if (theImgBrush.m_bOpaque) { theImgBrush.BltReplace( theImgBrush.m_pImg, theImgBrush.m_rcSelection.TopLeft() ); } else { theImgBrush.BltMatte( theImgBrush.m_pImg, theImgBrush.m_rcSelection.TopLeft() ); } }
InvalImgRect ( theImgBrush.m_pImg, &theImgBrush.m_rcSelection ); CommitImgRect( theImgBrush.m_pImg, &theImgBrush.m_rcSelection );
DirtyImg( theImgBrush.m_pImg ); }
/***************************************************************************/
void AddImgWnd(IMG* pimg, CImgWnd* pImgWnd) { ASSERT(pImgWnd->m_pNextImgWnd == NULL); pImgWnd->m_pNextImgWnd = pimg->m_pFirstImgWnd; pimg->m_pFirstImgWnd = pImgWnd; }
/***************************************************************************/
void GetImgSize(IMG* pImg, CSize& size) { size.cx = pImg->cxWidth; size.cy = pImg->cyHeight; }
/***************************************************************************/
BOOL SetImgSize(IMG* pImg, CSize newSize, BOOL bStretch) { if (newSize.cx != pImg->cxWidth || newSize.cy != pImg->cyHeight) { HBITMAP hNewBitmap = CreateCompatibleBitmap( pImg->hDC, newSize.cx, newSize.cy ); if (hNewBitmap == NULL) { return FALSE; } HDC hDC = CreateCompatibleDC( pImg->hDC );
if (hDC == NULL) { DeleteObject( hNewBitmap ); return FALSE; } HBITMAP hOldBitmap = (HBITMAP)SelectObject( hDC, hNewBitmap );
ASSERT( hOldBitmap );
HPALETTE hpalOld = NULL;
if (theApp.m_pPalette && theApp.m_pPalette->m_hObject) { hpalOld = SelectPalette( hDC, (HPALETTE)theApp.m_pPalette->m_hObject, FALSE ); // Background ??
RealizePalette( hDC ); }
if (bStretch) { UINT uStretch = HALFTONE;
if (pImg->cPlanes * pImg->cBitCount == 1) { uStretch = BLACKONWHITE;
if (GetRValue( crLeft ) || GetGValue( crLeft ) || GetBValue( crLeft )) uStretch = WHITEONBLACK; }
SetStretchBltMode( hDC, uStretch );
StretchCopy( hDC, 0, 0, newSize.cx, newSize.cy, pImg->hDC, 0, 0, pImg->cxWidth, pImg->cyHeight ); } else { // Fill it with the background color first!
HBRUSH hBrush = ::CreateSolidBrush(crRight);
ASSERT(hBrush);
if (hBrush) { HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC, hBrush);
ASSERT(hOldBrush);
PatBlt(hDC, 0, 0, newSize.cx, newSize.cy, PATCOPY);
VERIFY(SelectObject(hDC, hOldBrush) == hBrush);
DeleteObject(hBrush); }
BitBlt(hDC, 0, 0, newSize.cx, newSize.cy, pImg->hDC, 0, 0, SRCCOPY); }
if (hpalOld) SelectPalette( hDC, hpalOld, FALSE ); // Background ??
VERIFY( SelectObject( hDC, hOldBitmap) == hNewBitmap ); VERIFY( SelectObject( pImg->hDC, hNewBitmap) == pImg->hBitmap );
DeleteObject( pImg->hBitmap ); DeleteDC( hDC );
pImg->hBitmap = hNewBitmap; pImg->cxWidth = newSize.cx; pImg->cyHeight = newSize.cy;
pRubberImg = NULL;
SetupRubber( pImg );
InvalImgRect(pImg, NULL);
CImgWnd* pImgWnd = pImg->m_pFirstImgWnd;
while (pImgWnd) { pImgWnd->Invalidate( FALSE ); pImgWnd->CheckScrollBars();
pImgWnd = pImgWnd->m_pNextImgWnd; } }
return TRUE; }
/***************************************************************************/
// This may be set to TRUE via the "DriverCanStretch" entry in the INI file.
// Doing so will speed up the graphics editor, but will cause some device
// drivers to crash (hence the FALSE default).
//
BOOL g_bDriverCanStretch = TRUE;
void StretchCopy( HDC hdcDest, int xDest, int yDest, int cxDest, int cyDest, HDC hdcSrc , int xSrc , int ySrc , int cxSrc , int cySrc ) { if (cxDest == cxSrc && cyDest == cySrc) { // No point in using the trick if we're not really stretching...
BitBlt(hdcDest, xDest, yDest, cxDest, cyDest, hdcSrc, xSrc, ySrc, SRCCOPY); } else if (g_bDriverCanStretch || cxDest < 0 || cyDest < 0 || cxSrc < 0 || cySrc < 0) { // We can't use the following trick when flipping, but the
// driver will usually pass things on to GDI here anyway...
StretchBlt(hdcDest, xDest, yDest, cxDest, cyDest, hdcSrc, xSrc, ySrc, cxSrc, cySrc, SRCCOPY); } else { // Some drivers (e.g. Paradise) crash on memory to memory stretches,
// so we trick them into just using GDI here by not using SRCCOPY...
PatBlt(hdcDest, xDest, yDest, cxDest, cyDest, BLACKNESS);
StretchBlt(hdcDest, xDest, yDest, cxDest, cyDest, hdcSrc, xSrc, ySrc, cxSrc, cySrc, DSo); } }
/***************************************************************************/
void StandardiseCoords(CPoint* s, CPoint* e) { if (s->x > e->x) { int tx;
tx = s->x; s->x = e->x; e->x = tx; }
if (s->y > e->y) { int ty;
ty = s->y; s->y = e->y; e->y = ty; } }
/***************************************************************************/
CPalette* MergePalettes( CPalette *pPal1, CPalette *pPal2, int& iAdds ) { int iPal1NumEntries; int iPal2NumEntries; LOGPALETTE256 LogPal1; LOGPALETTE256 LogPal2; CPalette* pPalMerged = NULL;
iAdds = 0;
if (pPal1 == NULL || pPal2 == NULL) return NULL;
iPal1NumEntries = pPal1->GetPaletteEntries( 0, 256, &LogPal1.palPalEntry[0] ); pPal1->GetPaletteEntries( 0, iPal1NumEntries, &LogPal1.palPalEntry[0] );
iPal2NumEntries = pPal2->GetPaletteEntries( 0, 256, &LogPal2.palPalEntry[0] ); pPal2->GetPaletteEntries( 0, iPal2NumEntries, &LogPal2.palPalEntry[0] );
// check if room left in 1st palette to merge. If no room, then use 1st palette
for (int i = 0; i < iPal2NumEntries && iPal1NumEntries < MAX_PALETTE_COLORS; i++) { for (int j = 0; j < iPal1NumEntries; j++) { if (LogPal1.palPalEntry[j].peRed == LogPal2.palPalEntry[i].peRed && LogPal1.palPalEntry[j].peGreen == LogPal2.palPalEntry[i].peGreen && LogPal1.palPalEntry[j].peBlue == LogPal2.palPalEntry[i].peBlue) break; }
if (j < iPal1NumEntries) continue; // found one
// color was not found in 1st palette add it if room
LogPal1.palPalEntry[iPal1NumEntries++] = LogPal2.palPalEntry[i]; iAdds++; }
LogPal1.palVersion = 0x300; LogPal1.palNumEntries = (WORD)iPal1NumEntries;
pPalMerged = new CPalette();
if (pPalMerged) if (! CreateSafePalette(pPalMerged, (LPLOGPALETTE)&LogPal1 )) { delete pPalMerged; pPalMerged = NULL; }
return pPalMerged; }
/******************************************************************************/
void AdjustPointForGrid(CPoint *ptPointLocation) { if (theApp.m_iSnapToGrid != 0) { int iNextGridOffset;
iNextGridOffset = ptPointLocation->x % theApp.m_iGridExtent; // if distance to next grid is less than 1/2 distance between grids
// closer to previous grid
if (iNextGridOffset <= theApp.m_iGridExtent/2) { iNextGridOffset *= -1; // closer to previous grid location
} else { iNextGridOffset = theApp.m_iGridExtent -iNextGridOffset; // closer to next grid location
} ptPointLocation->x = ptPointLocation->x + iNextGridOffset;
// if distance to next grid is less than 1/2 distance between grids
// closer to previous grid
iNextGridOffset = ptPointLocation->y % theApp.m_iGridExtent; if (iNextGridOffset <= theApp.m_iGridExtent/2) { iNextGridOffset *= -1; // closer to previous grid location
} else { iNextGridOffset = theApp.m_iGridExtent -iNextGridOffset; // closer to next grid location
}
ptPointLocation->y = ptPointLocation->y + iNextGridOffset; } }
static unsigned short bmapHorzBorder [] = { 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0 };
static unsigned short bmapVertBorder [] = { 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 };
CBrush g_brSelectHorz; CBrush g_brSelectVert; static CBitmap m_bmSelectHorz; static CBitmap m_bmSelectVert;
void InitCustomData() // called once in main
{ //
// no windows critical error message box, return errors to open call
//
if (m_bmSelectHorz.CreateBitmap( 8, 8, 1, 1, (LPSTR)bmapHorzBorder )) g_brSelectHorz.CreatePatternBrush( &m_bmSelectHorz );
if (m_bmSelectVert.CreateBitmap( 8, 8, 1, 1, (LPSTR)bmapVertBorder )) g_brSelectVert.CreatePatternBrush( &m_bmSelectVert );
SetErrorMode( SEM_FAILCRITICALERRORS ); }
//
// make sure global resoures are freed
//
void CustomExit() { if (g_brSelectHorz.m_hObject) g_brSelectHorz.DeleteObject();
if (m_bmSelectHorz.m_hObject) m_bmSelectHorz.DeleteObject();
if (g_brSelectVert.m_hObject) g_brSelectVert.DeleteObject();
if (m_bmSelectVert.m_hObject) m_bmSelectVert.DeleteObject(); }
/*
int FileTypeFromExtension( const TCHAR far* lpcExt ) { if (*lpcExt == TEXT('.')) // skip the . in .*
lpcExt++;
// must be redone
return NULL; } */
CPalette *PBSelectPalette(CDC *pDC, CPalette *pPalette, BOOL bForceBk) { if (!pPalette) { return(NULL); }
if (IsInPlace()) { bForceBk = TRUE; }
CPalette *ppalOld = pDC->SelectPalette( theApp.m_pPalette, bForceBk ); pDC->RealizePalette();
return(ppalOld); }
|