#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); }