//============================================================================ // Copyright (C) Microsoft Corporation, 1996 - 1999 // // File: lcx.cpp // // History: // 07/13/96 Abolade Gbadegesin Created, based on C code by Steve Cobb // // Implements an enhanced list-control. //============================================================================ #include "stdafx.h" #include "resource.h" #include "util.h" #include "listctrl.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif IMPLEMENT_DYNAMIC(CListCtrlEx, CListCtrl) BEGIN_MESSAGE_MAP(CListCtrlEx, CListCtrl) //{{AFX_MSG_MAP(CListCtrlEx) ON_WM_LBUTTONDOWN() ON_WM_CHAR() ON_WM_KEYDOWN() //}}AFX_MSG_MAP END_MESSAGE_MAP() //---------------------------------------------------------------------------- // Function: CListCtrlEx::~CListCtrlEx // // Destructor. Deletes the image list, if any, and unloads row-information. //---------------------------------------------------------------------------- CListCtrlEx::~CListCtrlEx( ) { delete m_pimlChecks; } //---------------------------------------------------------------------------- // Function: CListCtrlEx::GetColumnCount // // Called to retrieve the number of columns in any list-control. //---------------------------------------------------------------------------- INT CListCtrlEx::GetColumnCount( ) { return Header_GetItemCount(ListView_GetHeader(m_hWnd)); } //---------------------------------------------------------------------------- // Function: CListCtrlEx::SetColumnText // // Sets the text in the header of the column in position 'iCol'. //---------------------------------------------------------------------------- BOOL CListCtrlEx::SetColumnText( INT iCol, LPCTSTR pszText, INT fmt ) { LV_COLUMN lvc; lvc.mask = LVCF_FMT | LVCF_TEXT; lvc.pszText = (LPTSTR)pszText; lvc.fmt = fmt; return SetColumn(iCol, &lvc); } //---------------------------------------------------------------------------- // Function: CListCtrlEx::InstallChecks // // Installs check-box handling for the list-control. //---------------------------------------------------------------------------- BOOL CListCtrlEx::InstallChecks( ) { HICON hIcon; // // Make sure the list-control is in report-mode // if (!(GetStyle() & LVS_REPORT)) { return FALSE; } // // Allocate a new image-list. // m_pimlChecks = new CImageList; if (!m_pimlChecks) { return FALSE; } do { // // Initialize the image-list // if (!m_pimlChecks->Create( ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), ILC_MASK, 2, 2 )) { break; } // // Add the icons for the checked and unchecked images // hIcon = ::LoadIcon( AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_COMMON_UNCHECK) ); if (!hIcon) { break; } m_pimlChecks->Add(hIcon); ::DeleteObject(hIcon); hIcon = ::LoadIcon( AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_COMMON_CHECK) ); if (!hIcon) { break; } m_pimlChecks->Add(hIcon); ::DeleteObject(hIcon); // // Replace the list-control's current image-list with the new one // m_pimlOldState = SetImageList(m_pimlChecks, LVSIL_STATE); return TRUE; } while(FALSE); // // If we arrive here, an error occurred, so clean up and fail // delete m_pimlChecks; m_pimlChecks = NULL; return FALSE; } //---------------------------------------------------------------------------- // Function: CListCtrlEx::UninstallChecks // // Uninstalls checkbox-handling for the list-control. //---------------------------------------------------------------------------- VOID CListCtrlEx::UninstallChecks( ) { if (!m_pimlChecks) { return; } if (m_pimlOldState) { SetImageList(m_pimlOldState, LVSIL_STATE); } delete m_pimlChecks; m_pimlChecks = NULL; } //---------------------------------------------------------------------------- // Function: CListCtrlEx::GetCheck // // Returns TRUE if the specified item is checked, FALSE otherwise. //---------------------------------------------------------------------------- BOOL CListCtrlEx::GetCheck( INT iItem ) { return !!(GetItemState(iItem, LVIS_STATEIMAGEMASK) & INDEXTOSTATEIMAGEMASK(LCXI_CHECKED)); } //---------------------------------------------------------------------------- // Function: CListCtrlEx::SetCheck // // If 'fCheck' is non-zero, checks 'iItem', otherwise clears 'iItem'. //---------------------------------------------------------------------------- VOID CListCtrlEx::SetCheck( INT iItem, BOOL fCheck ) { SetItemState( iItem, INDEXTOSTATEIMAGEMASK(fCheck ? LCXI_CHECKED : LCXI_UNCHECKED), LVIS_STATEIMAGEMASK ); if (GetParent()) { NMHDR nmh; nmh.code = LVXN_SETCHECK; nmh.hwndFrom = m_hWnd; ::SendMessage( GetParent()->m_hWnd, WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&nmh ); } } //---------------------------------------------------------------------------- // Function: CListCtrlEx::OnChar // // Handles the 'WM_CHAR' message for the list-control. // This allows users to change items' checked-states using the keyboard. //---------------------------------------------------------------------------- VOID CListCtrlEx::OnChar( UINT nChar, UINT nRepCnt, UINT nFlags ) { BOOL fSet = FALSE; BOOL fClear = FALSE; BOOL fToggle = FALSE; INT iItem; // // Handle characters with special meaning for us // switch (nChar) { case TEXT(' '): { fToggle = TRUE; break; } case TEXT('+'): case TEXT('='): { fSet = TRUE; break; } case TEXT('-'): { fClear = TRUE; break; } } if (!fToggle && !fSet && !fClear) { CListCtrl::OnChar(nChar, nRepCnt, nFlags); } else { // // Change the state of all the selected items // for (iItem = GetNextItem(-1, LVNI_SELECTED); iItem != -1; iItem = GetNextItem(iItem, LVNI_SELECTED)) { if (fToggle) { SetCheck(iItem, !GetCheck(iItem)); } else if (fSet) { if (!GetCheck(iItem)) { SetCheck(iItem, TRUE); } } else { if (GetCheck(iItem)) { SetCheck(iItem, FALSE); } } } } } //---------------------------------------------------------------------------- // Function: CListCtrlEx::OnKeyDown // // Handles the 'WM_KEYDOWN' message for the list-control. // This allows users to change items' checked-states using the keyboard. //---------------------------------------------------------------------------- VOID CListCtrlEx::OnKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags ) { // // We want the left-arrow treated as an up-arrow // and the right-arrow treated as a down-arrow. // if (nChar == VK_LEFT) { CListCtrl::OnKeyDown(VK_UP, nRepCnt, nFlags); return; } else if (nChar == VK_RIGHT) { CListCtrl::OnKeyDown(VK_DOWN, nRepCnt, nFlags); return; } CListCtrl::OnKeyDown(nChar, nRepCnt, nFlags); } //---------------------------------------------------------------------------- // Function: CListCtrlEx::OnLButtonDown // // Handles the 'WM_LBUTTONDOWN' message, changing an item's checked state // when the user clicks the item's check-image. //---------------------------------------------------------------------------- VOID CListCtrlEx::OnLButtonDown( UINT nFlags, CPoint pt ) { INT iItem; UINT uiFlags; // // If the left-mouse button is over the check-box icon, // we treat it as a toggle on the check-box. // uiFlags = 0; iItem = HitTest(pt, &uiFlags); if (iItem != -1 && (uiFlags & LVHT_ONITEMSTATEICON)) { SetCheck(iItem, !GetCheck(iItem)); // Redraw this item RedrawItems(iItem, iItem); } CListCtrl::OnLButtonDown(nFlags, pt); } //---------------------------------------------------------------------------- // Function: AdjustColumnWidth // // Called to adjust the width of column 'iCol' so that the string 'pszContent' // can be displayed in the column without truncation. // // If 'NULL' is specified for 'pszContent', the function adjusts the column // so that the first string in the column is displayed without truncation. // // Returns the new width of the column. //---------------------------------------------------------------------------- INT AdjustColumnWidth( IN CListCtrl& listCtrl, IN INT iCol, IN LPCTSTR pszContent ) { INT iWidth, iOldWidth; // // Compute the minimum width the column needs to be // if (pszContent) { iWidth = listCtrl.GetStringWidth(pszContent); } else { iWidth = listCtrl.GetStringWidth(listCtrl.GetItemText(0, iCol)); } // // Adjust 'iWidth' to leave some breathing space // iWidth += ::GetSystemMetrics(SM_CXSMICON) + ::GetSystemMetrics(SM_CXEDGE) * 2; // // If the column is narrower than 'iWidth', enlarge it. // iOldWidth = listCtrl.GetColumnWidth(iCol); if (iOldWidth < iWidth) { listCtrl.SetColumnWidth(iCol, iWidth); iOldWidth = iWidth; } return iOldWidth; } INT AdjustColumnWidth( IN CListCtrl& listCtrl, IN INT iCol, IN UINT idsContent ) { // Needed for Loadstring AFX_MANAGE_STATE(AfxGetStaticModuleState()); CString sCol; sCol.LoadString(idsContent); return AdjustColumnWidth(listCtrl, iCol, sCol); }