Move git root from Client/ to src/ to track all source code: - Client: Game client source (moved to Client/Client/) - Server: Game server source - GameTools: Development tools - CryptoSource: Encryption utilities - database: Database scripts - Script: Game scripts - rylCoder_16.02.2008_src: Legacy coder tools - GMFont, Game: Additional resources 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
733 lines
22 KiB
C++
733 lines
22 KiB
C++
// GridListCtrl.cpp : implementation file
|
|
//
|
|
#include "stdafx.h"
|
|
#include "GridListCtrl.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CGridListCtrl
|
|
|
|
CGridListCtrl::CGridListCtrl()
|
|
{
|
|
m_CurSubItem = -1;
|
|
m_pListEdit =NULL;
|
|
}
|
|
|
|
CGridListCtrl::~CGridListCtrl()
|
|
{
|
|
if( m_pListEdit)
|
|
{
|
|
delete m_pListEdit;
|
|
}
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CGridListCtrl, CListCtrl)
|
|
//{{AFX_MSG_MAP(CGridListCtrl)
|
|
ON_WM_LBUTTONDOWN()
|
|
ON_WM_HSCROLL()
|
|
ON_WM_VSCROLL()
|
|
ON_NOTIFY_REFLECT(LVN_BEGINLABELEDIT, OnBeginlabeledit)
|
|
ON_NOTIFY_REFLECT(LVN_ENDLABELEDIT, OnEndlabeledit)
|
|
//}}AFX_MSG_MAP
|
|
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CGridListCtrl message handlers
|
|
|
|
BOOL CGridListCtrl::PrepareControl(WORD wStyle)
|
|
{
|
|
m_wStyle = wStyle;
|
|
ASSERT( m_hWnd );
|
|
DWORD dwStyle = GetWindowLong(m_hWnd, GWL_STYLE);
|
|
dwStyle &= ~(LVS_TYPEMASK);
|
|
dwStyle &= ~(LVS_EDITLABELS);
|
|
|
|
// Make sure we have report view and send edit label messages.
|
|
SetWindowLong( m_hWnd, GWL_STYLE, dwStyle | LVS_REPORT );
|
|
|
|
// Enable the full row selection and the drag drop of headers.
|
|
DWORD styles = LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP ;
|
|
// Use macro since this is new and not in MFC.
|
|
ListView_SetExtendedListViewStyleEx(m_hWnd, styles, styles );
|
|
return TRUE;
|
|
}
|
|
|
|
void CGridListCtrl::OnLButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
LVHITTESTINFO ht;
|
|
ht.pt = point;
|
|
// Test for which subitem was clicked.
|
|
// Use macro since this is new and not in MFC.
|
|
int rval = ListView_SubItemHitTest( m_hWnd, &ht );
|
|
|
|
// Store the old column number and set the new column value.
|
|
int oldsubitem = m_CurSubItem;
|
|
m_CurSubItem = IndexToOrder( ht.iSubItem );
|
|
|
|
CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
|
|
// Make the column fully visible.
|
|
// We have to take into account that the columns may be reordered
|
|
MakeColumnVisible( Header_OrderToIndex( pHeader->m_hWnd, m_CurSubItem ) );
|
|
|
|
// Store old state of the item.
|
|
int state = GetItemState( ht.iItem, LVIS_FOCUSED );
|
|
|
|
// Call default left button click is here just before we might bail.
|
|
// Also updates the state of the item.
|
|
CListCtrl::OnLButtonDown(nFlags, point);
|
|
|
|
NMLISTVIEW nmlv;
|
|
nmlv.hdr.code = LVN_COLUMNCLICK;
|
|
nmlv.hdr.hwndFrom = GetSafeHwnd();
|
|
nmlv.hdr.idFrom = (UINT)(::GetMenu( GetSafeHwnd() ));
|
|
nmlv.iItem = ht.iItem;
|
|
nmlv.iSubItem = ht.iSubItem;
|
|
nmlv.uNewState = 0;
|
|
nmlv.uOldState = 0;
|
|
nmlv.uChanged = 0;
|
|
GetParent()->SendMessage( WM_NOTIFY, (WPARAM)0, (LPARAM)(&nmlv) );
|
|
|
|
// Bail if the state from before was not focused or the
|
|
// user has not already clicked on this cell.
|
|
if( !state
|
|
|| m_CurSubItem == -1
|
|
|| oldsubitem != m_CurSubItem )
|
|
{
|
|
RedrawItems( rval, rval );
|
|
return;
|
|
}
|
|
|
|
int doedit = 0;
|
|
// If we are in column 0 make sure that the user clicked on
|
|
// the item label.
|
|
if( 0 == ht.iSubItem )
|
|
{
|
|
if( ht.flags & LVHT_ONITEMLABEL ) doedit = 1;
|
|
}
|
|
else
|
|
{
|
|
doedit = 1;
|
|
}
|
|
if( !doedit ) return;
|
|
|
|
// check if focused column has editable attribute
|
|
if( GLCT_NORMAL == GetColumnType(ht.iSubItem) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Send Notification to parent of ListView ctrl
|
|
CString str;
|
|
str = GetItemText( ht.iItem, ht.iSubItem );
|
|
LV_DISPINFO dispinfo;
|
|
dispinfo.hdr.hwndFrom = m_hWnd;
|
|
dispinfo.hdr.idFrom = GetDlgCtrlID();
|
|
dispinfo.hdr.code = LVN_BEGINLABELEDIT;
|
|
|
|
dispinfo.item.mask = LVIF_TEXT;
|
|
dispinfo.item.iItem = ht.iItem;
|
|
dispinfo.item.iSubItem = ht.iSubItem;
|
|
dispinfo.item.pszText = (LPTSTR)((LPCTSTR)str);
|
|
dispinfo.item.cchTextMax = str.GetLength();
|
|
|
|
GetParent()->SendMessage( WM_NOTIFY, GetDlgCtrlID(),
|
|
(LPARAM)&dispinfo );
|
|
}
|
|
|
|
BOOL CGridListCtrl::PositionControl( CWnd * pWnd, int iItem, int iSubItem )
|
|
{
|
|
ASSERT( pWnd && pWnd->m_hWnd );
|
|
ASSERT( iItem >= 0 );
|
|
// Make sure that the item is visible
|
|
if( !EnsureVisible( iItem, TRUE ) ) return NULL;
|
|
|
|
// Make sure that nCol is valid
|
|
CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
|
|
int nColumnCount = pHeader->GetItemCount();
|
|
ASSERT( iSubItem >= 0 && iSubItem < nColumnCount );
|
|
if( iSubItem >= nColumnCount ||
|
|
// We have to take into account that the header may be reordered
|
|
GetColumnWidth(Header_OrderToIndex( pHeader->m_hWnd,iSubItem)) < 5 )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Get the header order array to sum the column widths up to the selected cell.
|
|
int *orderarray = new int[ nColumnCount ];
|
|
Header_GetOrderArray( pHeader->m_hWnd, nColumnCount, orderarray );
|
|
int offset = 0;
|
|
int i;
|
|
for( i = 0; orderarray[i] != iSubItem; i++ )
|
|
offset += GetColumnWidth( orderarray[i] );
|
|
int colwidth = GetColumnWidth( iSubItem );
|
|
delete[] orderarray;
|
|
|
|
CRect rect;
|
|
GetItemRect( iItem, &rect, LVIR_BOUNDS );
|
|
|
|
// Scroll if we need to expose the column
|
|
CRect rcClient;
|
|
GetClientRect( &rcClient );
|
|
if( offset + rect.left < 0 || offset + colwidth + rect.left > rcClient.right )
|
|
{
|
|
CSize size;
|
|
size.cx = offset + rect.left;
|
|
size.cy = 0;
|
|
Scroll( size );
|
|
rect.left -= size.cx;
|
|
}
|
|
|
|
rect.left += offset+4;
|
|
rect.right = rect.left + colwidth - 3 ;
|
|
// The right end of the control should not go past the edge
|
|
// of the grid control.
|
|
if( rect.right > rcClient.right)
|
|
rect.right = rcClient.right;
|
|
pWnd->MoveWindow( &rect );
|
|
|
|
return 1;
|
|
}
|
|
|
|
void CGridListCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
// This function is called by the control in different
|
|
// stages during the control drawing process.
|
|
|
|
NMLVCUSTOMDRAW *pCD = (NMLVCUSTOMDRAW*)pNMHDR;
|
|
// By default set the return value to do the default behavior.
|
|
*pResult = 0;
|
|
|
|
switch( pCD->nmcd.dwDrawStage )
|
|
{
|
|
case CDDS_PREPAINT: // First stage (for the whole control)
|
|
// Tell the control we want to receive drawing messages
|
|
// for drawing items.
|
|
*pResult = CDRF_NOTIFYITEMDRAW;
|
|
// The next stage is handled in the default:
|
|
break;
|
|
case CDDS_ITEMPREPAINT | CDDS_SUBITEM: // Stage three (called for each subitem of the focused item)
|
|
{
|
|
// We don't want to draw anything here, but we need to respond
|
|
// of DODEFAULT will be the next stage.
|
|
// Tell the control we want to handle drawing after the subitem
|
|
// is drawn.
|
|
*pResult = CDRF_NOTIFYSUBITEMDRAW | CDRF_NOTIFYPOSTPAINT;
|
|
}
|
|
break;
|
|
case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM: // Stage four (called for each subitem of the focused item)
|
|
{
|
|
// We do the drawing here (well maybe).
|
|
// This is actually after the control has done its drawing
|
|
// on the subitem. Since drawing a cell is near instantaneous
|
|
// the user won't notice.
|
|
int subitem = pCD->iSubItem;
|
|
// Only do our own drawing if this subitem has focus at the item level.
|
|
if( (pCD->nmcd.uItemState & CDIS_FOCUS) )
|
|
{
|
|
// If this subitem is the subitem with the current focus,
|
|
// draw it. Otherwise let the control draw it.
|
|
CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
|
|
// We have to take into account the possibility that the
|
|
// columns may be reordered.
|
|
if( subitem == Header_OrderToIndex( pHeader->m_hWnd, m_CurSubItem ) )
|
|
{
|
|
// POSTERASE
|
|
CDC* pDC = CDC::FromHandle(pCD->nmcd.hdc);
|
|
// Calculate the offset of the text from the right and left of the cell.
|
|
int offset = pDC->GetTextExtent(_T(" "), 1 ).cx*2;
|
|
// The rect for the cell gives correct left and right values.
|
|
CRect rect = pCD->nmcd.rc;
|
|
CRect bounds;
|
|
GetItemRect( pCD->nmcd.dwItemSpec, &bounds, LVIR_BOUNDS );
|
|
// Get the top and bottom from the item itself.
|
|
rect.top = bounds.top;
|
|
rect.bottom = bounds.bottom;
|
|
// Adjust rectangle for horizontal scroll and first column label
|
|
{
|
|
if( subitem == 0 )
|
|
{
|
|
CRect lrect;
|
|
GetItemRect( pCD->nmcd.dwItemSpec, &lrect, LVIR_LABEL );
|
|
rect.left = lrect.left;
|
|
rect.right = lrect.right;
|
|
}
|
|
else
|
|
{
|
|
rect.right += bounds.left;
|
|
rect.left += bounds.left;
|
|
}
|
|
}
|
|
// Clear the background with button face color
|
|
pDC->FillRect(rect, &CBrush(::GetSysColor(COLOR_HIGHLIGHT)));
|
|
|
|
// Draw column focus box
|
|
rect.DeflateRect( 1, 1 );
|
|
pDC->FrameRect(rect, &CBrush(::GetSysColor(COLOR_BTNTEXT)));
|
|
|
|
// Draw text
|
|
CString str;
|
|
str = GetItemText( pCD->nmcd.dwItemSpec, pCD->iSubItem );
|
|
|
|
rect.DeflateRect( 4, 1, 0, 0 );
|
|
pDC->SetTextColor( ::GetSysColor(COLOR_HIGHLIGHTTEXT) );
|
|
pDC->DrawText( str, rect,
|
|
DT_SINGLELINE|DT_NOPREFIX|DT_LEFT|DT_VCENTER|DT_END_ELLIPSIS);
|
|
|
|
// Tell the control that we handled the drawing for this subitem.*/
|
|
*pResult = CDRF_SKIPDEFAULT;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default: // Stage two handled here. (called for each item)
|
|
if( !(pCD->nmcd.uItemState & CDIS_FOCUS) )
|
|
{
|
|
// If this item does not have focus, let the
|
|
// control draw the whole item.
|
|
*pResult = CDRF_DODEFAULT;
|
|
}
|
|
else
|
|
{
|
|
// If this item has focus, tell the control we want
|
|
// to handle subitem drawing.
|
|
*pResult = CDRF_NOTIFYSUBITEMDRAW;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CGridListCtrl::MakeColumnVisible(int nCol)
|
|
{
|
|
if( nCol < 0 )
|
|
return;
|
|
// Get the order array to total the column offset.
|
|
CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
|
|
int colcount = pHeader->GetItemCount();
|
|
ASSERT( nCol < colcount );
|
|
int *orderarray = new int[ colcount ];
|
|
Header_GetOrderArray( pHeader->m_hWnd, colcount, orderarray );
|
|
// Get the column offset
|
|
int offset = 0;
|
|
for( int i = 0; orderarray[i] != nCol; i++ )
|
|
offset += GetColumnWidth( orderarray[i] );
|
|
int colwidth = GetColumnWidth( nCol );
|
|
delete[] orderarray;
|
|
|
|
CRect rect;
|
|
GetItemRect( 0, &rect, LVIR_BOUNDS );
|
|
|
|
// Now scroll if we need to expose the column
|
|
CRect rcClient;
|
|
GetClientRect( &rcClient );
|
|
if( offset + rect.left < 0 || offset + colwidth + rect.left > rcClient.right )
|
|
{
|
|
CSize size;
|
|
size.cx = offset + rect.left;
|
|
size.cy = 0;
|
|
Scroll( size );
|
|
rect.left -= size.cx;
|
|
}
|
|
}
|
|
|
|
BOOL CGridListCtrl::PreTranslateMessage(MSG* pMsg)
|
|
{
|
|
if(pMsg->message == WM_KEYDOWN)
|
|
{
|
|
// Handle the keystrokes for the left and right keys
|
|
// to move the cell selection left and right.
|
|
// Handle F2 to commence edit mode from the keyboard.
|
|
// Only handle these if the grid control has the focus.
|
|
// (Messages also come through here for the edit control
|
|
// and we don't want them.
|
|
if( this == GetFocus() )
|
|
{
|
|
switch( pMsg->wParam )
|
|
{
|
|
case VK_LEFT:
|
|
{
|
|
// Decrement the order number.
|
|
m_CurSubItem--;
|
|
if( m_CurSubItem < -1 )
|
|
{
|
|
// This indicates that the whole row is selected and F2 means nothing.
|
|
m_CurSubItem = -1;
|
|
}
|
|
else
|
|
{
|
|
CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
|
|
// Make the column visible.
|
|
// We have to take into account that the header
|
|
// may be reordered.
|
|
MakeColumnVisible( Header_OrderToIndex( pHeader->m_hWnd, m_CurSubItem ) );
|
|
// Invalidate the item.
|
|
int iItem = GetNextItem( -1, LVNI_FOCUSED );
|
|
if( iItem != -1 )
|
|
{
|
|
CRect rcBounds;
|
|
GetItemRect(iItem, rcBounds, LVIR_BOUNDS);
|
|
InvalidateRect( &rcBounds );
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
case VK_RIGHT:
|
|
{
|
|
// Increment the order number.
|
|
m_CurSubItem++;
|
|
CHeaderCtrl* pHeader = (CHeaderCtrl*) GetDlgItem(0);
|
|
int nColumnCount = pHeader->GetItemCount();
|
|
// Don't go beyond the last column.
|
|
if( m_CurSubItem > nColumnCount -1 )
|
|
{
|
|
m_CurSubItem = nColumnCount-1;
|
|
}
|
|
else
|
|
{
|
|
// We have to take into account that the header
|
|
// may be reordered.
|
|
MakeColumnVisible( Header_OrderToIndex( pHeader->m_hWnd, m_CurSubItem ) );
|
|
int iItem = GetNextItem( -1, LVNI_FOCUSED );
|
|
// Invalidate the item.
|
|
if( iItem != -1 )
|
|
{
|
|
CRect rcBounds;
|
|
GetItemRect(iItem, rcBounds, LVIR_BOUNDS);
|
|
InvalidateRect( &rcBounds );
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
case VK_F2: // Enter nondestructive edit mode.
|
|
{
|
|
int iItem = GetNextItem( -1, LVNI_FOCUSED );
|
|
if( m_CurSubItem != -1 && iItem != -1 &&
|
|
GLCT_EDIT == GetColumnType(m_CurSubItem) )
|
|
{
|
|
// Send Notification to parent of ListView ctrl
|
|
CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
|
|
CString str;
|
|
// We have to take into account that the header
|
|
// may be reordered.
|
|
str = GetItemText( iItem, Header_OrderToIndex( pHeader->m_hWnd, m_CurSubItem ) );
|
|
LV_DISPINFO dispinfo;
|
|
dispinfo.hdr.hwndFrom = m_hWnd;
|
|
dispinfo.hdr.idFrom = GetDlgCtrlID();
|
|
dispinfo.hdr.code = LVN_BEGINLABELEDIT;
|
|
|
|
dispinfo.item.mask = LVIF_TEXT;
|
|
dispinfo.item.iItem = iItem;
|
|
// We have to take into account that the header
|
|
// may be reordered.
|
|
dispinfo.item.iSubItem = Header_OrderToIndex( pHeader->m_hWnd, m_CurSubItem );
|
|
dispinfo.item.pszText = (LPTSTR)((LPCTSTR)str);
|
|
dispinfo.item.cchTextMax = str.GetLength();
|
|
// Send message to the parent that we are ready to edit.
|
|
GetParent()->SendMessage( WM_NOTIFY, GetDlgCtrlID(),
|
|
(LPARAM)&dispinfo );
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return CListCtrl::PreTranslateMessage(pMsg);
|
|
}
|
|
|
|
|
|
int CGridListCtrl::IndexToOrder( int iIndex )
|
|
{
|
|
// Since the control only provide the OrderToIndex macro,
|
|
// we have to provide the IndexToOrder. This translates
|
|
// a column index value to a column order value.
|
|
int nRet = -1;
|
|
CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
|
|
int colcount = pHeader->GetItemCount();
|
|
int *orderarray = new int[ colcount ];
|
|
Header_GetOrderArray( pHeader->m_hWnd, colcount, orderarray );
|
|
int i;
|
|
for( i=0; i<colcount; i++ )
|
|
{
|
|
if( orderarray[i] == iIndex )
|
|
{
|
|
nRet = i;
|
|
break;
|
|
}
|
|
}
|
|
delete[] orderarray;
|
|
return nRet;
|
|
}
|
|
|
|
void CGridListCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
|
|
{
|
|
if( GetFocus() != this ) SetFocus();
|
|
CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
|
|
}
|
|
|
|
void CGridListCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
|
|
{
|
|
if( GetFocus() != this ) SetFocus();
|
|
CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
|
|
}
|
|
|
|
void CGridListCtrl::OnBeginlabeledit(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
|
|
// TODO: Add your control notification handler code here
|
|
|
|
CString str = pDispInfo->item.pszText;
|
|
int item = pDispInfo->item.iItem;
|
|
int subitem = pDispInfo->item.iSubItem;
|
|
// Construct and create the custom multiline edit control.
|
|
// We could just as well have used a combobox, checkbox,
|
|
// rich text control, etc.
|
|
m_pListEdit = new CInPlaceEdit( item, subitem, str );
|
|
// Start with a small rectangle. We'll change it later.
|
|
CRect rect( 0,0,1,1 );
|
|
DWORD dwStyle = ES_LEFT;
|
|
dwStyle |= WS_BORDER|WS_CHILD|WS_VISIBLE;//|ES_MULTILINE|ES_AUTOVSCROLL;
|
|
m_pListEdit->Create( dwStyle, rect, this, 103 );
|
|
// Have the Grid position and size the custom edit control
|
|
this->PositionControl( m_pListEdit, item, subitem );
|
|
// Have the edit box size itself to its content.
|
|
m_pListEdit->CalculateSize();
|
|
// Return TRUE so that the list control will hnadle NOT edit label itself.
|
|
*pResult = 1;
|
|
}
|
|
|
|
void CGridListCtrl::OnEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
|
|
// TODO: Add your control notification handler code here
|
|
|
|
int item = pDispInfo->item.iItem;
|
|
int subitem = pDispInfo->item.iSubItem;
|
|
// This is coming from the grid list control notification.
|
|
if( m_pListEdit )
|
|
{
|
|
CString str;
|
|
if( pDispInfo->item.pszText )
|
|
{
|
|
this->SetItemText( item, subitem, pDispInfo->item.pszText );
|
|
}
|
|
delete m_pListEdit;
|
|
m_pListEdit = 0;
|
|
}
|
|
*pResult = 0;
|
|
}
|
|
|
|
void CGridListCtrl::SetColumnType( int nCol, GLC_COLUMNTYPE columnType )
|
|
{
|
|
if( nCol < 100 )
|
|
{
|
|
m_aColumnType[nCol] = columnType;
|
|
}
|
|
}
|
|
|
|
GLC_COLUMNTYPE CGridListCtrl::GetColumnType( int nCol )
|
|
{
|
|
if( nCol < 100 )
|
|
{
|
|
return m_aColumnType[nCol];
|
|
}
|
|
|
|
return GLCT_EDIT;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CInPlaceEdit
|
|
|
|
CInPlaceEdit::CInPlaceEdit(int iItem, int iSubItem, CString sInitText)
|
|
:m_sInitText( sInitText )
|
|
{
|
|
m_iItem = iItem;
|
|
m_iSubItem = iSubItem;
|
|
m_bESC = FALSE;
|
|
}
|
|
|
|
CInPlaceEdit::~CInPlaceEdit()
|
|
{
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CInPlaceEdit, CEdit)
|
|
//{{AFX_MSG_MAP(CInPlaceEdit)
|
|
ON_WM_KILLFOCUS()
|
|
ON_WM_CHAR()
|
|
ON_WM_CREATE()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CInPlaceEdit message handlers
|
|
|
|
BOOL CInPlaceEdit::PreTranslateMessage(MSG* pMsg)
|
|
{
|
|
if( pMsg->message == WM_KEYDOWN )
|
|
{
|
|
SHORT sKey = GetKeyState( VK_CONTROL);
|
|
if(pMsg->wParam == VK_RETURN
|
|
|| pMsg->wParam == VK_DELETE
|
|
|| pMsg->wParam == VK_ESCAPE
|
|
|| sKey
|
|
)
|
|
{
|
|
::TranslateMessage(pMsg);
|
|
/* Strange but true:
|
|
If the edit control has ES_MULTILINE and ESC
|
|
is pressed the parent is destroyed if the
|
|
message is dispatched. In this
|
|
case the parent is the list control. */
|
|
if( !(GetStyle() & ES_MULTILINE) || pMsg->wParam != VK_ESCAPE )
|
|
{
|
|
::DispatchMessage(pMsg);
|
|
}
|
|
return TRUE; // DO NOT process further
|
|
}
|
|
}
|
|
|
|
return CEdit::PreTranslateMessage(pMsg);
|
|
}
|
|
|
|
|
|
void CInPlaceEdit::OnKillFocus(CWnd* pNewWnd)
|
|
{
|
|
CEdit::OnKillFocus(pNewWnd);
|
|
|
|
CString str;
|
|
GetWindowText(str);
|
|
|
|
// Send Notification to parent of ListView ctrl
|
|
LV_DISPINFO dispinfo;
|
|
dispinfo.hdr.hwndFrom = GetParent()->m_hWnd;
|
|
dispinfo.hdr.idFrom = GetDlgCtrlID();
|
|
dispinfo.hdr.code = LVN_ENDLABELEDIT;
|
|
|
|
dispinfo.item.mask = LVIF_TEXT;
|
|
dispinfo.item.iItem = m_iItem;
|
|
dispinfo.item.iSubItem = m_iSubItem;
|
|
dispinfo.item.pszText = m_bESC ? NULL : LPTSTR((LPCTSTR)str);
|
|
dispinfo.item.cchTextMax = m_bESC ? 0 : str.GetLength();
|
|
|
|
GetParent()->GetParent()->SendMessage( WM_NOTIFY, GetParent()->GetDlgCtrlID(),
|
|
(LPARAM)&dispinfo );
|
|
|
|
}
|
|
|
|
|
|
void CInPlaceEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
|
|
{
|
|
if( nChar == VK_ESCAPE || nChar == VK_RETURN)
|
|
{
|
|
if( nChar == VK_ESCAPE )
|
|
m_bESC = TRUE;
|
|
GetParent()->SetFocus();
|
|
return;
|
|
}
|
|
|
|
CEdit::OnChar(nChar, nRepCnt, nFlags);
|
|
|
|
// Resize edit control if needed
|
|
CalculateSize();
|
|
}
|
|
|
|
int CInPlaceEdit::OnCreate(LPCREATESTRUCT lpCreateStruct)
|
|
{
|
|
if (CEdit::OnCreate(lpCreateStruct) == -1)
|
|
return -1;
|
|
|
|
// Set the proper font
|
|
CFont* font = GetParent()->GetFont();
|
|
SetFont(font);
|
|
|
|
SetWindowText( m_sInitText );
|
|
SetFocus();
|
|
CalculateSize();
|
|
SetSel( 0, -1 );
|
|
return 0;
|
|
}
|
|
|
|
void CInPlaceEdit::CalculateSize()
|
|
{
|
|
// Get text extent
|
|
CString str;
|
|
|
|
GetWindowText( str );
|
|
CWindowDC dc(this);
|
|
CFont *pFont = GetParent()->GetFont();
|
|
CFont *pFontDC = dc.SelectObject( pFont );
|
|
CSize size;
|
|
|
|
// Get client rect
|
|
CRect rect, parentrect;
|
|
GetClientRect( &rect );
|
|
GetParent()->GetClientRect( &parentrect );
|
|
|
|
// Transform rect to parent coordinates
|
|
ClientToScreen( &rect );
|
|
GetParent()->ScreenToClient( &rect );
|
|
|
|
if( !(GetStyle() & ES_MULTILINE ) )
|
|
{
|
|
size = dc.GetTextExtent( str );
|
|
dc.SelectObject( pFontDC );
|
|
size.cx += 5; // add some extra buffer
|
|
}
|
|
else
|
|
{
|
|
CRect thinrect( rect ); // To measure the skinniest text box
|
|
CRect widerect( rect ); // To measure the wides text box
|
|
widerect.right = parentrect.right;
|
|
// Use the shortest of the two box sizes.
|
|
int thinheight = dc.DrawText( str, &thinrect, DT_CALCRECT|DT_NOPREFIX|DT_LEFT|DT_EXPANDTABS|DT_WORDBREAK );
|
|
int wideheight = dc.DrawText( str, &widerect, DT_CALCRECT|DT_NOPREFIX|DT_LEFT|DT_EXPANDTABS|DT_WORDBREAK );
|
|
if( thinheight >= wideheight )
|
|
{
|
|
size.cy = wideheight + 5;
|
|
size.cx = widerect.right - widerect.left + 5;
|
|
}
|
|
else
|
|
{
|
|
size.cy = thinheight + 5;
|
|
size.cx = thinrect.right - thinrect.left + 5;
|
|
}
|
|
}
|
|
|
|
// Check whether control needs to be resized
|
|
// and whether there is space to grow
|
|
int changed = 0;
|
|
if( size.cx > rect.Width() )
|
|
{
|
|
if( size.cx + rect.left < parentrect.right-2 )
|
|
rect.right = rect.left + size.cx;
|
|
else
|
|
rect.right = parentrect.right-2;
|
|
changed = 1;
|
|
}
|
|
if( size.cy > rect.Height() )
|
|
{
|
|
if( size.cy + rect.top < parentrect.bottom-2 )
|
|
rect.bottom = rect.top + size.cy;
|
|
else
|
|
{
|
|
rect.bottom = parentrect.bottom-2;
|
|
ShowScrollBar( SB_VERT );
|
|
}
|
|
changed = 1;
|
|
}
|
|
// If the size became larger rposition the window.
|
|
if( changed )
|
|
MoveWindow( &rect );
|
|
}
|