📄 gridbtncellbase.cpp
字号:
{
}
void CGridBtnCellBase::OnDblClick( CPoint PointCellRelative)
{
ProcessCtlClick(WM_LBUTTONDBLCLK, // Command that invoked. e.g. WM_LBUTTONDOWN
PointCellRelative); // point to check for hit
}
BOOL CGridBtnCellBase::GetTextRect( LPRECT pRect) // i/o: i=dims of cell rect; o=dims of text rect
{
CGridCtrl* pGrid = GetGrid();
ASSERT( pGrid);
CRect RectCell( *pRect);
// any button images
ASSERT( MAX_NBR_CTLS_INCELL > GetDrawCtlNbrMax() ); // whoa!
CRect RectAry[ MAX_NBR_CTLS_INCELL];
const int iCtlNbr = GetDrawCtlNbr();
if( iCtlNbr > 0)
{
if( CalcDrawCtlRects( RectAry, // returns: CRects with coordinates
// last entry has optional leftover rect
// available for text, etc.
MAX_NBR_CTLS_INCELL,// nbr of Rects in above array
*pRect) ) // cell rectangle to work with
{
// allowable text area has shrunk up
*pRect = RectAry[ iCtlNbr];
pRect->left += GetMargin();
pRect->right -= GetMargin();
}
}
// I've modified the starting point before passing to base
return CGridCellBase::GetTextRect( pRect);
}
CSize CGridBtnCellBase::GetCellExtent(CDC* pDC)
{
CSize sizeBase = CGridCellBase::GetCellExtent(pDC);
// any button images?
int iCtlNbr = GetDrawCtlNbr();
if( iCtlNbr > 0)
{
int iDefaultWidth = sizeBase.cy;
int iWidthTotal = 0;
int iWidth;
CSize SizeText;
LOGFONT lf;
memcpy(&lf, GetFont(), sizeof(LOGFONT));
CFont font;
font.CreateFontIndirect(&lf);
CFont* pOldFont = pDC->SelectObject(&font);
CRect rectText;
for( int i1=0; i1 < iCtlNbr; i1++)
{
iWidth = GetDrawCtlWidth( i1);
if( iWidth <= 0)
{
const char* pszBtnText = GetDrawCtlBtnText( i1);
if( pszBtnText == NULL)
{
iWidth = iDefaultWidth;
}
else
{
// use width of text in button as a gauge
rectText.SetRectEmpty();
pDC->DrawText( pszBtnText, strlen( pszBtnText), &rectText, GetFormat() | DT_CALCRECT);
iWidth = rectText.Width();
}
}
iWidthTotal += iWidth;
}
pDC->SelectObject(pOldFont);
sizeBase += CSize( iWidthTotal + 4*GetMargin(), 0);
}
return sizeBase;
}
// Simplify by just using drawing logic for printing, too
BOOL CGridBtnCellBase::PrintCell(CDC* pDC, int nRow, int nCol, CRect rect)
{
return Draw( pDC, nRow, nCol, rect);
}
//////////////////////////////////////////////////////////
/*****************************************************************************
Called during all the mouse events associated with clicking a control
embedded within a cell. Override to have more elaborate handling like
implementing radio button logic.
*****************************************************************************/
BOOL CGridBtnCellBase::ClickedCellCtl( UINT uMsg, // Command that invoked. e.g. WM_LBUTTONDOWN
int aiWhich) // zero-based index of image to draw
// returns: T=redraw occurred / F=no redraw
{
if( aiWhich < 0
|| aiWhich >= GetDrawCtlNbrMax() )
{
ASSERT( FALSE);
return FALSE;
}
UINT uiState = GetDrawCtlState( aiWhich);
if( uiState & DFCS_INACTIVE)
return FALSE; // button is inactive -- don't do anything
m_sLastCtlClicked = (short)aiWhich;
UINT iType = GetDrawCtlType( aiWhich);
switch( uMsg)
{
case WM_LBUTTONDOWN:
// appears pushed in
uiState |= DFCS_PUSHED;
SetDrawCtlState( aiWhich, uiState);
break;
case WM_LBUTTONUP:
case WM_LBUTTONDBLCLK:
// appears pushed out
uiState &= (~DFCS_PUSHED);
// auto check / uncheck controls, too
if( iType == DFC_BUTTON )
{
BOOL bIsMbrRadioGrp = GetDrawCtlIsMbrRadioGrp( aiWhich);
if( uiState & DFCS_BUTTONRADIO
|| bIsMbrRadioGrp )
{
// radio buttons or any button flagged as being part
// of a radio group will be made to look pressed down
// while pushing-up / unchecking all other members
// of the radio group
const int iCtlNbr = GetDrawCtlNbr();
UINT uiStateRadio;
for( int i1=0; i1 < iCtlNbr; i1++)
{
if( i1 != aiWhich)
{
uiStateRadio = GetDrawCtlState( i1);
bIsMbrRadioGrp = GetDrawCtlIsMbrRadioGrp( i1);
if( uiStateRadio & DFCS_BUTTONRADIO
|| bIsMbrRadioGrp )
{
uiStateRadio &= (~( DFCS_PUSHED | DFCS_CHECKED) );
// push out and uncheck
SetDrawCtlState( i1, uiStateRadio);
}
}
}
uiState |= DFCS_CHECKED; // check
if( !(uiState & DFCS_BUTTONRADIO) )
uiState |= DFCS_PUSHED; // press in if not real radio button
}
else if( !( uiState & ALL_BUT_BTN_CHK) )
{
// not a pushbutton -- it's a check box
// (can't check for DFCS_BUTTONCHECK directly since it is bit 0)
if( uiState & DFCS_CHECKED)
uiState &= (~DFCS_CHECKED); // uncheck
else
uiState |= DFCS_CHECKED; // check
}
}
SetDrawCtlState( aiWhich, uiState);
break;
default:
ASSERT( FALSE); // gotta handle new message
return FALSE;
}
CGridCtrl* pGrid = GetGrid();
ASSERT( pGrid);
pGrid->RedrawCell( m_iRow, m_iCol);
return TRUE;
}
/*****************************************************************************
Processes mouse clicks that potentially hit an embedded cell control
*****************************************************************************/
BOOL CGridBtnCellBase::ProcessCtlClick(UINT uMsg, // Command that invoked. e.g. WM_LBUTTONDOWN
const CPoint& arPoint) // point to check for hit
// returns: T=hit a control / F=no control hit
{
int iCtlHit = RelPointInCtl( arPoint); // Relative point coords
// returns: Index of control that this point is within bounds of or -1 if no control matches
if( iCtlHit >= 0)
{
ClickedCellCtl( uMsg, // Command that invoked. e.g. WM_LBUTTONDOWN
iCtlHit); // zero-based index of image to draw
return TRUE;
}
m_sLastCtlClicked = -1;
return FALSE;
}
int CGridBtnCellBase::RelPointInCtl( const CPoint& arPoint) // Relative point coords
// returns: Index of control that this point is within bounds of or -1 if no control matches
{
CGridCtrl* pGrid = GetGrid();
ASSERT( pGrid);
CRect RectCell;
if( pGrid->GetCellRect( m_iRow,
m_iCol,
&RectCell) )
{
ASSERT( MAX_NBR_CTLS_INCELL > GetDrawCtlNbrMax() ); // whoa!
CRect RectAry[ MAX_NBR_CTLS_INCELL];
if( CalcDrawCtlRects( RectAry, // returns: CRects with coordinates
// last entry has optional leftover rect
// available for text, etc.
MAX_NBR_CTLS_INCELL,// nbr of Rects in above array
RectCell) ) // cell rectangle to work with
{
const int iCtlNbr = GetDrawCtlNbr();
// make point absolute coord
CPoint pointAbs;
pointAbs.x = arPoint.x + RectCell.left;
pointAbs.y = arPoint.y + RectCell.top;
for( int i1=0; i1 < iCtlNbr; i1++)
{
if( pointAbs.x >= RectAry[i1].left
&& pointAbs.x <= RectAry[i1].right
&& pointAbs.y >= RectAry[i1].top
&& pointAbs.y <= RectAry[i1].bottom)
{
return i1; // found it
}
}
}
}
return -1;
}
/*****************************************************************************
Determines bounding rectangle to draw a button in a cell. Used to draw cells
and for mouse hit testing.
If a fixed-size control can't fit within the cell, the control will shrink in
the required x and / or y dimension. I do this because I'm not using a
clipping region when I display the cell -- that would be a better solution.
*****************************************************************************/
BOOL CGridBtnCellBase::CalcDrawCtlRects(CRect* apRect, // returns: CRects with coordinates
// last entry has optional leftover rect
// available for text, etc.
int aiNbrRectEntries, // nbr of Rects in above array
const CRect& arRectCell)// cell rectangle to work with
// returns: success / fail
{
ASSERT( apRect != NULL);
if( aiNbrRectEntries < GetDrawCtlNbrMax() )
{
ASSERT( FALSE); // need to allow for leftover rect
return FALSE;
}
const int iCtlNbr = GetDrawCtlNbr();
if( iCtlNbr <= 0)
return FALSE;
int i1, i2;
int iSpinBoxDownIdx = -1; // can have zero or 1 spin box -- no more
// identifies placment of down arrow of the spin box
int iWidth = 0;
CTL_ALIGN CtlAlign;
UINT uiType;
UINT uiState;
CRect* pRectSav = apRect;
// calculate the width layout of buttons by examining
// all of them and noting important info
int iFixedSum = 0;
int iSizeToFitCount = 0;
for( i1=0; i1 < iCtlNbr; i1++)
{
CtlAlign = GetDrawCtlAlign( i1);
if( CtlAlign == CTL_ALIGN_CENTER)
{
// forget all calculations if any are centered, all controls
// just overwrite each other and expand to fit cell
for( i2=0; i2 < iCtlNbr; i2++)
{
apRect->operator=( arRectCell); // copy initial rectangle
apRect++;
}
apRect->operator=( CRect(0,0,0,0) ); // no text leftover
return TRUE;
}
iWidth = GetDrawCtlWidth( i1);
if( iWidth > 0)
iFixedSum += iWidth;
else
iSizeToFitCount++;
// spin box rectangles are stacked on top of each other
// thus, avoid doubling spin box width
if( iSpinBoxDownIdx < 0)
{
uiState = GetDrawCtlState( i1);
if( GetDrawCtlType( i1) == DFC_SCROLL
&& !( uiState & (DFCS_SCROLLCOMBOBOX
| DFCS_SCROLLDOWN
| DFCS_SCROLLLEFT
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -