www.pudn.com > RichEditGrid_src.zip > GridCellRich.cpp


// GridCellRich.cpp: implementation of the CGridCellRich class. 
// 
// GridCellRich Demonstration 
// ************************** 
// 
// Written by Mathieu DUBAËLE (mathieu@appstmd.com) 
// 
// Feel free to send me all the changes you can made to this code. 
////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include "gridctrl_src/gridctrl.h" 
#include "RichEditGrid.h" 
#include "GridCellRich.h" 
#include "InPlaceRichEdit.h" 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
IMPLEMENT_DYNCREATE(CGridCellRich, CGridCell) 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
CGridCellRich::CGridCellRich() 
{ 
	m_pRichEditTemp=(CRichEditCtrl*) AfxGetMainWnd ()->GetDlgItem (IDC_RICHEDIT_TEMP); 
	ASSERT(m_pRichEditTemp!=NULL); 
} 
 
CGridCellRich::~CGridCellRich() 
{ 
 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CallBack functions 
 
static DWORD CALLBACK EditStreamCallBack(DWORD dwCookie, LPBYTE pbBuff, LONG cb,  
					LONG *pcb) 
{ 
	CString *pstr = (CString *)dwCookie; 
 
	if( pstr->GetLength() < cb ) 
	{ 
		*pcb = pstr->GetLength(); 
		memcpy(pbBuff, (LPCSTR)*pstr, *pcb ); 
		pstr->Empty(); 
	} 
	else 
	{ 
		*pcb = cb; 
		memcpy(pbBuff, (LPCSTR)*pstr, *pcb ); 
		*pstr = pstr->Right( pstr->GetLength() - cb ); 
	} 
	return 0; 
} 
 
 
 
///////////////////////////////////////////////////////////////////////////// 
BOOL CGridCellRich::Draw(CDC* pDC, int nRow, int nCol, CRect rect,  BOOL bEraseBkgnd /*=TRUE*/) 
{ 
    // Note - all through this function we totally brutalise 'rect'. Do not 
    // depend on it's value being that which was passed in. 
 
    CGridCtrl* pGrid = GetGrid(); 
    ASSERT(pGrid); 
 
    if (!pGrid || !pDC) 
        return FALSE; 
 
    if( rect.Width() <= 0 || rect.Height() <= 0)  // prevents imagelist item from drawing even 
        return FALSE;                             //  though cell is hidden 
 
    //TRACE3("Drawing %scell %d, %d\n", IsFixed()? _T("Fixed ") : _T(""), nRow, nCol); 
 
    int nSavedDC = pDC->SaveDC(); 
    pDC->SetBkMode(TRANSPARENT); 
 
    // Get the default cell implementation for this kind of cell. We use it if this cell 
    // has anything marked as "default" 
    CGridDefaultCell *pDefaultCell = (CGridDefaultCell*) GetDefaultCell(); 
    if (!pDefaultCell) 
        return FALSE; 
 
    // Set up text and background colours 
    COLORREF TextClr, TextBkClr; 
 
    TextClr = (GetTextClr() == CLR_DEFAULT)? pDefaultCell->GetTextClr() : GetTextClr(); 
    if (GetBackClr() == CLR_DEFAULT) 
        TextBkClr = pDefaultCell->GetBackClr(); 
    else 
    { 
        bEraseBkgnd = TRUE; 
        TextBkClr = GetBackClr(); 
    } 
 
    // Draw cell background and highlighting (if necessary) 
    if ( IsFocused() || IsDropHighlighted() ) 
    { 
        // Always draw even in list mode so that we can tell where the 
        // cursor is at.  Use the highlight colors though. 
        if(GetState() & GVIS_SELECTED) 
        { 
            TextBkClr = ::GetSysColor(COLOR_HIGHLIGHT); 
            TextClr = ::GetSysColor(COLOR_HIGHLIGHTTEXT); 
            bEraseBkgnd = TRUE; 
        } 
 
        rect.right++; rect.bottom++;    // FillRect doesn't draw RHS or bottom 
        if (bEraseBkgnd) 
        { 
            TRY  
            { 
                CBrush brush(TextBkClr); 
                pDC->FillRect(rect, &brush); 
            }  
            CATCH(CResourceException, e) 
            { 
                //e->ReportError(); 
            } 
            END_CATCH 
        } 
 
        // Don't adjust frame rect if no grid lines so that the 
        // whole cell is enclosed. 
        if(pGrid->GetGridLines() != GVL_NONE) 
        { 
            rect.right--; 
            rect.bottom--; 
        } 
 
        if (pGrid->GetFrameFocusCell()) 
        { 
                // Use same color as text to outline the cell so that it shows 
                // up if the background is black. 
            TRY  
            { 
                CBrush brush(TextClr); 
                pDC->FrameRect(rect, &brush); 
            } 
            CATCH(CResourceException, e) 
            { 
                //e->ReportError(); 
            } 
            END_CATCH 
        } 
        pDC->SetTextColor(TextClr); 
 
        // Adjust rect after frame draw if no grid lines 
        if(pGrid->GetGridLines() == GVL_NONE) 
        { 
            rect.right--; 
            rect.bottom--; 
        } 
 
		rect.DeflateRect(0,1,1,1);  
    } 
    else if ((GetState() & GVIS_SELECTED)) 
    { 
        rect.right++; rect.bottom++;    // FillRect doesn't draw RHS or bottom 
        pDC->FillSolidRect(rect, ::GetSysColor(COLOR_HIGHLIGHT)); 
        rect.right--; rect.bottom--; 
        pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT)); 
    } 
    else 
    { 
        if (bEraseBkgnd) 
        { 
            rect.right++; rect.bottom++;    // FillRect doesn't draw RHS or bottom 
            CBrush brush(TextBkClr); 
            pDC->FillRect(rect, &brush); 
            rect.right--; rect.bottom--; 
        } 
        pDC->SetTextColor(TextClr); 
    } 
 
    // Draw lines only when wanted 
    if (IsFixed() && pGrid->GetGridLines() != GVL_NONE) 
    { 
        CCellID FocusCell = pGrid->GetFocusCell(); 
 
        // As above, always show current location even in list mode so 
        // that we know where the cursor is at. 
        BOOL bHiliteFixed = pGrid->GetTrackFocusCell() && pGrid->IsValid(FocusCell) && 
                            (FocusCell.row == nRow || FocusCell.col == nCol); 
 
        // If this fixed cell is on the same row/col as the focus cell, 
        // highlight it. 
        if (bHiliteFixed) 
        { 
            rect.right++; rect.bottom++; 
            pDC->DrawEdge(rect, BDR_SUNKENINNER /*EDGE_RAISED*/, BF_RECT); 
            rect.DeflateRect(1,1); 
        } 
        else 
        { 
            CPen lightpen(PS_SOLID, 1,  ::GetSysColor(COLOR_3DHIGHLIGHT)), 
                darkpen(PS_SOLID,  1, ::GetSysColor(COLOR_3DDKSHADOW)), 
                *pOldPen = pDC->GetCurrentPen(); 
 
            pDC->SelectObject(&lightpen); 
            pDC->MoveTo(rect.right, rect.top); 
            pDC->LineTo(rect.left, rect.top); 
            pDC->LineTo(rect.left, rect.bottom); 
 
            pDC->SelectObject(&darkpen); 
            pDC->MoveTo(rect.right, rect.top); 
            pDC->LineTo(rect.right, rect.bottom); 
            pDC->LineTo(rect.left, rect.bottom); 
 
            pDC->SelectObject(pOldPen); 
            rect.DeflateRect(1,1); 
        } 
    } 
 
    // Draw Text and image 
#if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING) 
    if (!pDC->m_bPrinting) 
#endif 
    { 
        CFont *pFont = GetFontObject(); 
		ASSERT(pFont); 
        if (pFont) 
            pDC->SelectObject(pFont); 
    } 
 
    rect.DeflateRect(GetMargin(), 0); 
 
    if (pGrid->GetImageList() && GetImage() >= 0) 
    { 
        IMAGEINFO Info; 
        if (pGrid->GetImageList()->GetImageInfo(GetImage(), &Info)) 
        { 
            //  would like to use a clipping region but seems to have issue 
            //  working with CMemDC directly.  Instead, don't display image 
            //  if any part of it cut-off 
            // 
            // CRgn rgn; 
            // rgn.CreateRectRgnIndirect(rect); 
            // pDC->SelectClipRgn(&rgn); 
            // rgn.DeleteObject(); 
 
            int nImageWidth = Info.rcImage.right-Info.rcImage.left+1; 
            int nImageHeight = Info.rcImage.bottom-Info.rcImage.top+1; 
 
            if( nImageWidth + rect.left <= rect.right + (int)(2*GetMargin()) 
                && nImageHeight + rect.top <= rect.bottom + (int)(2*GetMargin())  ) 
            { 
                pGrid->GetImageList()->Draw(pDC, GetImage(), rect.TopLeft(), ILD_NORMAL); 
            } 
 
            //rect.left += nImageWidth+GetMargin(); 
        } 
    } 
 
    // Draw sort arrow 
    if (pGrid->GetSortColumn() == nCol && nRow == 0) 
    { 
        CSize size = pDC->GetTextExtent(_T("M")); 
        int nOffset = 2; 
 
        // Base the size of the triangle on the smaller of the column 
        // height or text height with a slight offset top and bottom. 
        // Otherwise, it can get drawn outside the bounds of the cell. 
        size.cy -= (nOffset * 2); 
 
        if (size.cy >= rect.Height()) 
            size.cy = rect.Height() - (nOffset * 2); 
 
        size.cx = size.cy;      // Make the dimensions square 
 
        // Kludge for vertical text 
        BOOL bVertical = (GetFont()->lfEscapement == 900); 
 
        // Only draw if it'll fit! 
        if (size.cx + rect.left < rect.right + (int)(2*GetMargin())) 
        { 
            int nTriangleBase = rect.bottom - nOffset - size.cy;    // Triangle bottom right 
            //int nTriangleBase = (rect.top + rect.bottom - size.cy)/2; // Triangle middle right 
            //int nTriangleBase = rect.top + nOffset;                 // Triangle top right 
 
            //int nTriangleLeft = rect.right - size.cx;                 // Triangle RHS 
            //int nTriangleLeft = (rect.right + rect.left - size.cx)/2; // Triangle middle 
            //int nTriangleLeft = rect.left;                            // Triangle LHS 
 
            int nTriangleLeft; 
            if (bVertical) 
                nTriangleLeft = (rect.right + rect.left - size.cx)/2; // Triangle middle 
            else 
                nTriangleLeft = rect.right - size.cx;               // Triangle RHS 
 
            CPen penShadow(PS_SOLID, 0, ::GetSysColor(COLOR_3DSHADOW)); 
            CPen penLight(PS_SOLID, 0, ::GetSysColor(COLOR_3DHILIGHT)); 
            if (pGrid->GetSortAscending()) 
            { 
                // Draw triangle pointing upwards 
                CPen *pOldPen = (CPen*) pDC->SelectObject(&penLight); 
                pDC->MoveTo( nTriangleLeft + 1, nTriangleBase + size.cy + 1); 
                pDC->LineTo( nTriangleLeft + (size.cx / 2) + 1, nTriangleBase + 1 ); 
                pDC->LineTo( nTriangleLeft + size.cx + 1, nTriangleBase + size.cy + 1); 
                pDC->LineTo( nTriangleLeft + 1, nTriangleBase + size.cy + 1); 
 
                pDC->SelectObject(&penShadow); 
                pDC->MoveTo( nTriangleLeft, nTriangleBase + size.cy ); 
                pDC->LineTo( nTriangleLeft + (size.cx / 2), nTriangleBase ); 
                pDC->LineTo( nTriangleLeft + size.cx, nTriangleBase + size.cy ); 
                pDC->LineTo( nTriangleLeft, nTriangleBase + size.cy ); 
                pDC->SelectObject(pOldPen); 
            } 
            else 
            { 
                // Draw triangle pointing downwards 
                CPen *pOldPen = (CPen*) pDC->SelectObject(&penLight); 
                pDC->MoveTo( nTriangleLeft + 1, nTriangleBase + 1 ); 
                pDC->LineTo( nTriangleLeft + (size.cx / 2) + 1, nTriangleBase + size.cy + 1 ); 
                pDC->LineTo( nTriangleLeft + size.cx + 1, nTriangleBase + 1 ); 
                pDC->LineTo( nTriangleLeft + 1, nTriangleBase + 1 ); 
     
                pDC->SelectObject(&penShadow); 
                pDC->MoveTo( nTriangleLeft, nTriangleBase ); 
                pDC->LineTo( nTriangleLeft + (size.cx / 2), nTriangleBase + size.cy ); 
                pDC->LineTo( nTriangleLeft + size.cx, nTriangleBase ); 
                pDC->LineTo( nTriangleLeft, nTriangleBase ); 
                pDC->SelectObject(pOldPen); 
            } 
             
            if (!bVertical) 
                rect.right -= size.cy; 
        } 
    } 
 
 
	// Format the text and render it 
    GetTextRect(rect); 
	FORMATRANGE fr; 
	UINT Left=::MulDiv(rect.left, 1440, pDC->GetDeviceCaps(LOGPIXELSX)); 
	UINT Top=::MulDiv(rect.top, 1440, pDC->GetDeviceCaps(LOGPIXELSY)); 
	UINT Right=::MulDiv(rect.right, 1440, pDC->GetDeviceCaps(LOGPIXELSX)); 
	UINT Bottom=::MulDiv(rect.bottom, 1440, pDC->GetDeviceCaps(LOGPIXELSY)); 
	CRect Rect (Left,Top,Right,Bottom); 
	fr.hdc = pDC->m_hDC; 
	fr.hdcTarget = pDC->m_hDC; 
	fr.rc = Rect; 
	fr.rcPage = Rect; 
	fr.chrg.cpMin = 0; 
	fr.chrg.cpMax = -1; 
	CString Text=GetText (); 
	UINT StreamType; 
	if (Text.Left (6)=="{\\rtf1") 
		StreamType=SF_RTF; 
	else 
		StreamType=SF_TEXT; 
	EDITSTREAM es = {(DWORD)&Text, 0, EditStreamCallBack}; 
	m_pRichEditTemp->SetSel (0,-1); 
	m_pRichEditTemp->SetBackgroundColor (FALSE,TextBkClr); 
	m_pRichEditTemp->Clear (); 
	m_pRichEditTemp->StreamIn(StreamType, es); 
	m_pRichEditTemp->FormatRange(&fr, TRUE); 
 
	// Update the display with the new formatting 
	m_pRichEditTemp->GetClientRect (&Rect); 
	m_pRichEditTemp->DisplayBand(&Rect); 
 
    pDC->RestoreDC(nSavedDC); 
 
    return TRUE; 
} 
 
 
BOOL CGridCellRich::Edit(int nRow, int nCol, CRect rect, CPoint /* point */, UINT nID, UINT nChar) 
{ 
    if ( m_bEditing ) 
	{       
        if (m_pEditWnd) 
		    m_pEditWnd->SendMessage ( WM_CHAR, nChar );     
    }   
	else   
	{    
		DWORD dwStyle = ES_LEFT; 
		if (GetFormat() & DT_RIGHT)  
			dwStyle = ES_RIGHT; 
		else if (GetFormat() & DT_CENTER)  
			dwStyle = ES_CENTER; 
		 
		m_bEditing = TRUE; 
		 
		// InPlaceEdit auto-deletes itself 
		CGridCtrl* pGrid = GetGrid(); 
		m_pEditWnd = new CInPlaceRichEdit((CWnd*) pGrid, rect, dwStyle, nID, nRow, nCol, GetText(), nChar); 
    } 
    return TRUE; 
} 
 
void CGridCellRich::SetBold () 
{ 
	if (!m_bEditing) return; 
	CHARFORMAT CharFormat; 
	CharFormat.cbSize=sizeof(CharFormat); 
	CharFormat.dwMask=CFM_BOLD; 
	CharFormat.dwEffects=CFE_BOLD; 
	CRichEditCtrl* pRich=(CRichEditCtrl*) m_pEditWnd; 
	pRich->SetSelectionCharFormat (CharFormat); 
} 
void CGridCellRich::SetItalic () 
{ 
	if (!m_bEditing) return; 
	CHARFORMAT CharFormat; 
	CharFormat.cbSize=sizeof(CharFormat); 
	CharFormat.dwMask=CFM_ITALIC; 
	CharFormat.dwEffects=CFE_ITALIC; 
	CRichEditCtrl* pRich=(CRichEditCtrl*) m_pEditWnd; 
	pRich->SetSelectionCharFormat (CharFormat); 
} 
void CGridCellRich::SetUnderline () 
{ 
	if (!m_bEditing) return; 
	CHARFORMAT CharFormat; 
	CharFormat.cbSize=sizeof(CharFormat); 
	CharFormat.dwMask=CFM_UNDERLINE; 
	CharFormat.dwEffects=CFE_UNDERLINE; 
	CRichEditCtrl* pRich=(CRichEditCtrl*) m_pEditWnd; 
	pRich->SetSelectionCharFormat (CharFormat); 
}