BOOL CSHListCtrl::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 CSHListCtrl::OnLButtonDblClk(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default 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 ); // 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 ) 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 ); // My code end here CListCtrl::OnLButtonDblClk(nFlags, point); }
BOOL CMySuperGrid::OnVkReturn() { BOOL bResult=FALSE; int iItem = GetNextItem( -1, LVNI_ALL | LVNI_SELECTED); if( GetCurSubItem() != -1 && iItem != -1) { CTreeItem*pSelItem = GetTreeItem(iItem); if(pSelItem!=NULL) { CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0); int iSubItem = Header_OrderToIndex(pHeader->m_hWnd, GetCurSubItem()); CItemInfo* pInfo = GetData(pSelItem); CItemInfo::CONTROLTYPE ctrlType; if(pInfo->GetControlType(iSubItem-1, ctrlType)) { switch(ctrlType) { /*put in your own control here*/ case pInfo->CONTROLTYPE::datecontrol:break; case pInfo->CONTROLTYPE::spinbutton:break; case pInfo->CONTROLTYPE::dropdownlistviewwhatevercontrol:break; case pInfo->CONTROLTYPE::combobox: { CStringList* list=NULL; pInfo->GetListData(iSubItem-1, list); CComboBox * pList = ShowList(iItem, iSubItem, list); bResult=TRUE; //I'll handle it from here }break; default:break; } } } } return bResult; }
CSHInPlaceEdit* CSHListCtrl::ShowInPlaceEditEx(int nItem, int nSubitem, DWORD dwStyle) { CSHInPlaceEdit* pEdit = new CSHInPlaceEdit(nItem, nSubitem); CRect rect(0,0,1,1); dwStyle |= ES_LEFT | WS_BORDER | WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL; pEdit->Create(dwStyle, rect, this, IDC_INPLACE_EDIT); CSHInPlaceButton* pButton = new CSHInPlaceButton(nItem, nSubitem); dwStyle = WS_CHILD | WS_VISIBLE; pButton->Create("...", dwStyle, rect, this, IDC_INPLACE_BUTTON); pEdit->SetButtonCtrl(pButton); pButton->SetEditCtrl(pEdit); // if (!EnsureVisible(nItem, TRUE)) return NULL; // Make sure that nCol is valid CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0); int nColumnCount = pHeader->GetItemCount(); ASSERT(nSubitem >= 0 && nSubitem < nColumnCount); if (nSubitem >= nColumnCount || // We have to take into account that the header may be reordered GetColumnWidth(Header_OrderToIndex( pHeader->m_hWnd, nSubitem)) < 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] != nSubitem; i++) offset += GetColumnWidth(orderarray[i]); int colwidth = GetColumnWidth(nSubitem); delete[] orderarray; GetItemRect(nItem, &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; rect.bottom--; CRect rcButton; rcButton = rect; rcButton.left = rcButton.right - rcButton.Height(); rect.right = rect.right - rect.Height(); pEdit->MoveWindow(&rect); pButton->MoveWindow(&rcButton); // PositionControl(pEdit, nItem, nSubitem); pEdit->CalculateSize(); pEdit->GetWindowRect( &rect ); rect.left = rect.right; rect.right += rect.Height(); ScreenToClient( &rect ); pButton->MoveWindow(&rect); CString sText = GetItemText(nItem, nSubitem); pEdit->SetWindowText(sText); pEdit->SetSel(0, -1); return pEdit; }
///////////////////////////////////////////////////////////////////////////// // CSHListCtrl message handlers void CSHListCtrl::OnLButtonDown(UINT nFlags, CPoint point) { LVHITTESTINFO ht; ht.pt = point; int rval = SubItemHitTest(&ht); 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); if (m_CurSubItem == -1 || ht.iItem == -1) { if(ht.iItem == -1) { NMLISTVIEW dispinfo; dispinfo.hdr.hwndFrom = m_hWnd; dispinfo.hdr.idFrom = GetDlgCtrlID(); dispinfo.hdr.code = NM_CLICK; dispinfo.iItem = -1; dispinfo.iSubItem = ht.iSubItem; GetParent()->SendMessage( WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&dispinfo ); } return; } // Call default left button click is here just before we might bail. // Also updates the state of the item. if (m_bClickEdit) m_bKeyEvent = FALSE; CListCtrl::OnLButtonDown(nFlags, point); // Bail if the state from before was not focused or the // user has not already clicked on this cell. if (!m_bClickEdit) { if( !state || m_CurSubItem == -1 || oldsubitem != m_CurSubItem ) 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; } // 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 CSHListCtrl::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() ) { if (m_bClickEdit) m_bKeyEvent = TRUE; 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 ) { // 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; case VK_RETURN: { // 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 ); } } // int iItem = GetNextItem( -1, LVNI_FOCUSED ); if( m_CurSubItem != -1 && iItem != -1 ) { // 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); } } return TRUE; default: break; } } } m_tooltip.RelayEvent(pMsg); return CListCtrl::PreTranslateMessage(pMsg); }
void CSHListCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult) { // This function is called by the control in different // stages during the control drawing process. if (!m_bKeyEvent) return; 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_3DFACE))); // PREPAINT CString str; str = GetItemText( pCD->nmcd.dwItemSpec, pCD->iSubItem ); // Deflate the rect by the horizontal offset. rect.DeflateRect( offset, 0 ); // You could also make this column alignment sensitive here. pDC->DrawText( str, rect, DT_SINGLELINE|DT_NOPREFIX|DT_LEFT|DT_VCENTER|DT_END_ELLIPSIS); // POSTPAINT // Draw rounded edge rect.InflateRect( offset, 0 ); pDC->Draw3dRect( &rect, ::GetSysColor(COLOR_3DSHADOW), ::GetSysColor(COLOR_3DFACE) ); rect.DeflateRect( 1, 1 ); pDC->Draw3dRect( &rect, ::GetSysColor(COLOR_3DDKSHADOW), ::GetSysColor(COLOR_3DHILIGHT) ); // 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; } }
// // MouseToItem // // Return the line+column information from the specified mouse coordinates // GVRow *GridView::MouseToItem(int mx, int my, ULONG *pline, ULONG *pcol, ULONG *puPortion, RECT *prect, GVITEM **gvitem) { RECT rect; ULONG line = 0, col = 0, portion = GHT_NONE; GetActiveClientRect(&rect); // clip mouse to edge of window if(mx < rect.left) mx = rect.left; if(my < rect.top) my = rect.top; if(my >= rect.bottom) my = rect.bottom - 1; if(mx >= rect.right) mx = rect.right - 1; // take the head-control into account my -= m_nHeaderHeight; mx += m_nHScrollPos; // work out the visual line-number line = my / m_nLineHeight + m_nVScrollPos; if(line >= m_gvData.VisibleRows()) line = m_gvData.VisibleRows()-1; if(gvitem) *gvitem = 0; GVRow *rowptr = m_gvData.GetRow(line); // check each column to see which was clicked in for(UINT i = 0; rowptr && i < m_nNumColumns; i++) { RECT rect; ULONG lidx = Header_OrderToIndex(m_hWndHeader, i); Header_GetItemRect(m_hWndHeader, lidx, &rect); // have we clicked in this item? perform a hittest to see what // part of the item was clicked (i.e. tree/icon/text etc) if(mx >= rect.left && mx < rect.right) { int treepos = rect.left;//0; int iconpos = rect.left;//0; if(prect) SetRect(prect, rect.left, line * m_nLineHeight + m_nHeaderHeight, rect.right, (line +1) * m_nLineHeight + m_nHeaderHeight - 1); // if this is column#0 then it contains the tree-hierarchy graphics if(lidx == 0) { treepos += rowptr->TreeIndent() * LEVEL_WIDTH; iconpos = treepos + LEVEL_WIDTH; if(rowptr->HasChildren() == false) treepos += LEVEL_WIDTH; } // clicked somewhere in the tree? if(mx < treepos) { portion = GHT_TREELINE; } else if(mx >= treepos && mx < iconpos) { portion = GHT_TREEBUTTON; } // clicked on the icon? else if(mx >= iconpos && mx < iconpos + 16) { portion = GHT_ICON; } // otherwise it's on the item itself else { portion = GHT_TEXT; } if(gvitem) *gvitem = &rowptr->items[lidx]; col = lidx; break; } } if(pcol) *pcol = col; if(puPortion) *puPortion = portion; if(pline) *pline = line; return rowptr; }
void CXTPSkinObjectHeader::OnDraw(CDC* pDC) { CXTPClientRect rcClient(this); CRect rcBackground(rcClient); CXTPBufferDC dc(*pDC, rcClient); BOOL bFilterBar = (GetStyle() & HDS_FILTERBAR) && XTPSystemVersion()->GetComCtlVersion() >= MAKELONG(80, 5); CRect rcFilter(0, 0, 0, 0); dc.FillSolidRect(rcClient, GetColor(COLOR_3DFACE)); if (bFilterBar) { INT cyFilter = (rcClient.Height() - 1)/2; rcFilter = rcClient; rcClient.bottom = rcClient.top + cyFilter; rcFilter.top = rcClient.bottom; DefWindowProc(WM_PAINT, (WPARAM)dc.GetSafeHdc(), 0); } CXTPSkinManagerClass* pClass = GetSkinClass(); CXTPFontDC fontDC(&dc, GetFont()); dc.SetTextColor(GetColor(COLOR_BTNTEXT)); dc.SetBkMode(TRANSPARENT); CHeaderCtrl* pHeaderCtrl = (CHeaderCtrl*)this; int iItemCount = pHeaderCtrl->GetItemCount(); // Draw each header item for (int iItem = 0; iItem < iItemCount; ++iItem) { int nIndex = Header_OrderToIndex(m_hWnd, iItem); // initialize draw item structure. CRect rcItem(0, 0, 0, 0); Header_GetItemRect(m_hWnd, nIndex, &rcItem); if ((rcItem.right < rcClient.left) || (rcItem.left > rcClient.right)) continue; if (bFilterBar) { rcItem.bottom = rcFilter.top; } int nState = HIS_NORMAL; if (nIndex == m_nHotItem) { nState = m_bLBtnDown ? HIS_PRESSED : HIS_HOT; } rcBackground.left = max(rcBackground.left, rcItem.right); pClass->DrawThemeBackground(&dc, HP_HEADERITEM, nState, &rcItem); DrawItemEntry(&dc, nIndex, rcItem, nState); } if (rcBackground.left < rcBackground.right) pClass->DrawThemeBackground(&dc, 0, 0, &rcBackground); }