📄 mulelistctrl.cpp
字号:
//////////////////////////////////
// MuleListCtrl.cpp
// : implementation file
//
#include "stdafx.h"
#include "emule.h"
#include "memdc.h"
#include "MuleListCtrl.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#define MLC_BLEND(A, B, X) ((A + B * (X-1) + ((X+1)/2)) / X)
#define MLC_RGBBLEND(A, B, X) ( \
RGB(MLC_BLEND(GetRValue(A), GetRValue(B), X), \
MLC_BLEND(GetGValue(A), GetGValue(B), X), \
MLC_BLEND(GetBValue(A), GetBValue(B), X)) \
)
#define MLC_DT_TEXT (DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER | DT_END_ELLIPSIS)
#define MLC_IDC_MENU 4875
#define MLC_IDC_UPDATE (MLC_IDC_MENU - 1)
//a value that's not a multiple of 4 and uncommon
#define MLC_MAGIC 0xFEEBDEEF
//used for very slow assertions
//#define MLC_ASSERT(f) ASSERT(f)
#define MLC_ASSERT(f) ((void)0)
//////////////////////////////////
// CMuleListCtrl
IMPLEMENT_DYNAMIC(CMuleListCtrl, CListCtrl)
CMuleListCtrl::CMuleListCtrl(PFNLVCOMPARE pfnCompare, DWORD dwParamSort) {
m_SortProc = pfnCompare;
m_dwParamSort = dwParamSort;
m_bCustomDraw = false;
m_iCurrentSortItem = -1;
m_iColumnsTracked = 0;
m_aColumns = NULL;
m_iRedrawCount = 0;
//just in case
m_crWindow = 0;
m_crWindowText = 0;
m_crHighlight = 0;
m_crFocusLine = 0;
m_crNoHighlight = 0;
m_crNoFocusLine = 0;
}
CMuleListCtrl::~CMuleListCtrl() {
if(m_aColumns != NULL)
delete[] m_aColumns;
}
int CMuleListCtrl::SortProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) {
return 0;
}
void CMuleListCtrl::SetName(LPCTSTR lpszName) {
m_Name = lpszName;
}
void CMuleListCtrl::PreSubclassWindow() {
SetColors();
CListCtrl::PreSubclassWindow();
ModifyStyle(LVS_SINGLESEL|LVS_LIST|LVS_ICON|LVS_SMALLICON,LVS_REPORT|TVS_LINESATROOT|TVS_HASBUTTONS);
SetExtendedStyle(LVS_EX_HEADERDRAGDROP);
}
int CMuleListCtrl::IndexToOrder(CHeaderCtrl* pHeader, int iIndex) {
int iCount = pHeader->GetItemCount();
int *piArray = new int[iCount];
Header_GetOrderArray( pHeader->m_hWnd, iCount, piArray);
for(int i=0; i < iCount; i++ ) {
if(piArray[i] == iIndex) {
delete[] piArray;
return i;
}
}
delete[] piArray;
return -1;
}
void CMuleListCtrl::HideColumn(int iColumn) {
CHeaderCtrl* pHeaderCtrl = GetHeaderCtrl();
int iCount = pHeaderCtrl->GetItemCount();
if(iColumn < 1 || iColumn >= iCount || m_aColumns[iColumn].bHidden)
return;
//stop it from redrawing
SetRedraw(FALSE);
//shrink width to 0
HDITEM item;
item.mask = HDI_WIDTH;
pHeaderCtrl->GetItem(iColumn, &item);
m_aColumns[iColumn].iWidth = item.cxy;
item.cxy = 0;
pHeaderCtrl->SetItem(iColumn, &item);
//move to front of list
INT *piArray = new INT[m_iColumnsTracked];
pHeaderCtrl->GetOrderArray(piArray, m_iColumnsTracked);
int iFrom = m_aColumns[iColumn].iLocation;
for(int i = 0; i < m_iColumnsTracked; i++)
if(m_aColumns[i].iLocation > m_aColumns[iColumn].iLocation && m_aColumns[i].bHidden)
iFrom++;
for(int i = iFrom; i > 0; i--)
piArray[i] = piArray[i - 1];
piArray[0] = iColumn;
pHeaderCtrl->SetOrderArray(m_iColumnsTracked, piArray);
delete[] piArray;
//update entry
m_aColumns[iColumn].bHidden = true;
//redraw
SetRedraw(TRUE);
Invalidate(FALSE);
}
void CMuleListCtrl::ShowColumn(int iColumn) {
CHeaderCtrl* pHeaderCtrl = GetHeaderCtrl();
int iCount = pHeaderCtrl->GetItemCount();
if(iColumn < 1 || iColumn >= iCount || !m_aColumns[iColumn].bHidden)
return;
//stop it from redrawing
SetRedraw(FALSE);
//restore position in list
INT *piArray = new INT[m_iColumnsTracked];
pHeaderCtrl->GetOrderArray(piArray, m_iColumnsTracked);
int iCurrent = IndexToOrder(pHeaderCtrl, iColumn);
for(; iCurrent < IndexToOrder(pHeaderCtrl, 0) && iCurrent < m_iColumnsTracked - 1; iCurrent++ )
piArray[iCurrent] = piArray[iCurrent + 1];
for(; m_aColumns[iColumn].iLocation > m_aColumns[pHeaderCtrl->OrderToIndex(iCurrent + 1)].iLocation &&
iCurrent < m_iColumnsTracked - 1; iCurrent++)
piArray[iCurrent] = piArray[iCurrent + 1];
piArray[iCurrent] = iColumn;
pHeaderCtrl->SetOrderArray(m_iColumnsTracked, piArray);
delete[] piArray;
//and THEN restore original width
HDITEM item;
item.mask = HDI_WIDTH;
item.cxy = m_aColumns[iColumn].iWidth;
pHeaderCtrl->SetItem(iColumn, &item);
//update entry
m_aColumns[iColumn].bHidden = false;
//redraw
SetRedraw(TRUE);
Invalidate(FALSE);
}
void CMuleListCtrl::SaveSettings(CPreferences::Table tID) {
INT *piArray = new INT[m_iColumnsTracked];
for(int i = 0; i < m_iColumnsTracked; i++) {
theApp.glob_prefs->SetColumnWidth(tID, i, GetColumnWidth(i));
theApp.glob_prefs->SetColumnHidden(tID, i, IsColumnHidden(i));
piArray[i] = m_aColumns[i].iLocation;
}
theApp.glob_prefs->SetColumnOrder(tID, piArray);
delete[] piArray;
}
void CMuleListCtrl::LoadSettings(CPreferences::Table tID) {
CHeaderCtrl* pHeaderCtrl = GetHeaderCtrl();
INT *piArray = new INT[m_iColumnsTracked];
for(int i = 0; i < m_iColumnsTracked; i++)
piArray[i] = i;
for(int i = 0; i < m_iColumnsTracked; i++) {
int iWidth = theApp.glob_prefs->GetColumnWidth(tID, i);
if(iWidth != 0)
SetColumnWidth(i, iWidth);
if(i == 0) {
piArray[0] = 0;
} else {
int iOrder = theApp.glob_prefs->GetColumnOrder(tID, i);
if(iOrder > 0 && iOrder < m_iColumnsTracked && iOrder != i)
piArray[iOrder] = i;
}
}
pHeaderCtrl->SetOrderArray(m_iColumnsTracked, piArray);
pHeaderCtrl->GetOrderArray(piArray, m_iColumnsTracked);
for(int i = 0; i < m_iColumnsTracked; i++)
m_aColumns[piArray[i]].iLocation = i;
delete[] piArray;
for(int i = 1; i < m_iColumnsTracked; i++) {
if(theApp.glob_prefs->GetColumnHidden(tID, i))
HideColumn(i);
}
}
void CMuleListCtrl::SetColors() {
m_crWindow = ::GetSysColor(COLOR_WINDOW);
m_crWindowText = ::GetSysColor(COLOR_WINDOWTEXT);
COLORREF crHighlight = ::GetSysColor(COLOR_HIGHLIGHT);
m_crFocusLine = crHighlight;
m_crNoHighlight = MLC_RGBBLEND(crHighlight, m_crWindow, 8);
m_crNoFocusLine = MLC_RGBBLEND(crHighlight, m_crWindow, 2);
m_crHighlight = MLC_RGBBLEND(crHighlight, m_crWindow, 4);
}
void CMuleListCtrl::SetSortArrow(int iColumn, ArrowType atType) {
HDITEM headerItem;
headerItem.mask = HDI_FORMAT | HDI_BITMAP;
CHeaderCtrl* pHeaderCtrl = GetHeaderCtrl();
//delete old image if column has changed
if(iColumn != m_iCurrentSortItem) {
pHeaderCtrl->GetItem(m_iCurrentSortItem, &headerItem);
headerItem.fmt &= ~(HDF_BITMAP | HDF_BITMAP_ON_RIGHT);
if (headerItem.hbm != 0) {
DeleteObject(headerItem.hbm);
headerItem.hbm = 0;
}
pHeaderCtrl->SetItem(m_iCurrentSortItem, &headerItem);
m_iCurrentSortItem = iColumn;
}
//place new arrow unless we were given an invalid column
if(iColumn >= 0 && pHeaderCtrl->GetItem(iColumn, &headerItem)) {
m_atSortArrow = atType;
if (headerItem.hbm != 0) {
DeleteObject(headerItem.hbm);
headerItem.hbm = 0;
}
headerItem.fmt |= HDF_BITMAP | HDF_BITMAP_ON_RIGHT;
headerItem.hbm = (HBITMAP)LoadImage(AfxGetInstanceHandle(),
MAKEINTRESOURCE(m_atSortArrow), IMAGE_BITMAP, 0, 0,
LR_LOADMAP3DCOLORS);
pHeaderCtrl->SetItem(iColumn, &headerItem);
}
}
int CMuleListCtrl::MoveItem(int iOldIndex, int iNewIndex) { //move item in list, returns index of new item
if(iNewIndex > iOldIndex)
iNewIndex--;
//save substrings
CString *strs;
DWORD Style = GetStyle();
if((Style & LVS_OWNERDATA) == 0) {
strs = new CString[m_iColumnsTracked];
for(int i = 0; i < m_iColumnsTracked; i++)
strs[i] = GetItemText(iOldIndex, i);
}
//copy item
LVITEM lvi;
TCHAR szText[256];
lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM | LVIF_INDENT | LVIF_IMAGE;
lvi.stateMask = (UINT)-1;
lvi.iItem = iOldIndex;
lvi.iSubItem = 0;
lvi.pszText = szText;
lvi.cchTextMax = sizeof(szText) / sizeof(szText[0]);
lvi.iIndent = 0;
if(GetItem(&lvi) == 0)
return -1;
lvi.iItem = iNewIndex;
//do the move
SetRedraw(FALSE);
//SetItemData(iOldIndex, 0); //should do this to be safe?
DeleteItem(iOldIndex);
iNewIndex = InsertItem(&lvi);
SetRedraw(TRUE);
//restore substrings
if((Style & LVS_OWNERDATA) == 0) {
for(int i = 0; i < m_iColumnsTracked; i++) {
//SetItemText(iNewIndex, i, strs[i]);
LVITEM lvi;
lvi.iSubItem = i;
lvi.pszText = (LPTSTR)((LPCTSTR)strs[i]);
DefWindowProc(LVM_SETITEMTEXT, iNewIndex, (LPARAM)&lvi);
}
delete[] strs;
}
return iNewIndex;
}
int CMuleListCtrl::UpdateLocation(int iItem) {
int iItemCount = GetItemCount();
if(iItem >= iItemCount || iItem < 0)
return iItem;
BOOL notLast = iItem + 1 < iItemCount;
BOOL notFirst = iItem > 0;
DWORD_PTR dwpItemData = GetItemData(iItem);
if(dwpItemData == NULL)
return iItem;
if(notFirst) {
int iNewIndex = iItem - 1;
POSITION pos = m_Params.FindIndex(iNewIndex);
int iResult = m_SortProc(dwpItemData, GetParamAt(pos, iNewIndex), m_dwParamSort);
if(iResult < 0) {
POSITION posPrev = pos;
int iDist = iNewIndex / 2;
while(iDist > 1) {
for(int i = 0; i < iDist; i++)
m_Params.GetPrev(posPrev);
if(m_SortProc(dwpItemData, GetParamAt(posPrev, iNewIndex - iDist), m_dwParamSort) < 0) {
iNewIndex = iNewIndex - iDist;
pos = posPrev;
} else {
posPrev = pos;
}
iDist /= 2;
}
while(--iNewIndex >= 0) {
m_Params.GetPrev(pos);
if(m_SortProc(dwpItemData, GetParamAt(pos, iNewIndex), m_dwParamSort) >= 0)
break;
}
MoveItem(iItem, iNewIndex + 1);
return iNewIndex + 1;
}
}
if(notLast) {
int iNewIndex = iItem + 1;
POSITION pos = m_Params.FindIndex(iNewIndex);
int iResult = m_SortProc(dwpItemData, GetParamAt(pos, iNewIndex), m_dwParamSort);
if(iResult > 0) {
POSITION posNext = pos;
int iDist = (GetItemCount() - iNewIndex) / 2;
while(iDist > 1) {
for(int i = 0; i < iDist; i++)
m_Params.GetNext(posNext);
if(m_SortProc(dwpItemData, GetParamAt(posNext, iNewIndex + iDist), m_dwParamSort) > 0) {
iNewIndex = iNewIndex + iDist;
pos = posNext;
} else {
posNext = pos;
}
iDist /= 2;
}
while(++iNewIndex < iItemCount) {
m_Params.GetNext(pos);
if(m_SortProc(dwpItemData, GetParamAt(pos, iNewIndex), m_dwParamSort) <= 0)
break;
}
MoveItem(iItem, iNewIndex);
return iNewIndex;
}
}
return iItem;
}
DWORD_PTR CMuleListCtrl::GetItemData(int iItem) {
POSITION pos = m_Params.FindIndex(iItem);
LPARAM lParam = GetParamAt(pos, iItem);
MLC_ASSERT(lParam == CListCtrl::GetItemData(iItem));
return lParam;
}
//lower level than everything else so poorly overriden functions don't break us
BOOL CMuleListCtrl::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) {
//lets look for the important messages that are essential to handle
switch(message) {
case WM_NOTIFY:
if(wParam == 0) {
if(((NMHDR*)lParam)->code == NM_RCLICK) {
//handle right click on headers and show column menu
POINT point;
GetCursorPos (&point);
CTitleMenu tmColumnMenu;
tmColumnMenu.CreatePopupMenu();
if(m_Name.GetLength() != 0)
tmColumnMenu.AddMenuTitle(m_Name);
CHeaderCtrl *pHeaderCtrl = GetHeaderCtrl();
int iCount = pHeaderCtrl->GetItemCount();
for(int iCurrent = 1; iCurrent < iCount; iCurrent++) {
HDITEM item;
char text[255];
item.pszText = text;
item.mask = HDI_TEXT;
item.cchTextMax = 255;
pHeaderCtrl->GetItem(iCurrent, &item);
tmColumnMenu.AppendMenu(MF_STRING | m_aColumns[iCurrent].bHidden ? 0 : MF_CHECKED,
MLC_IDC_MENU + iCurrent, item.pszText);
}
tmColumnMenu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this);
tmColumnMenu.DestroyMenu();
return *pResult = TRUE;
} else if(((NMHDR*)lParam)->code == HDN_BEGINTRACKA || ((NMHDR*)lParam)->code == HDN_BEGINTRACKW) {
//stop them from changeing the size of anything "before" first column
HD_NOTIFY *pHDN = (HD_NOTIFY*)lParam;
if(m_aColumns[pHDN->iItem].bHidden)
return *pResult = TRUE;
} else if(((NMHDR*)lParam)->code == HDN_ENDDRAG) {
//stop them from moving first column
NMHEADER *pHeader = (NMHEADER*)lParam;
if(pHeader->iItem != 0 && pHeader->pitem->iOrder != 0) {
int iNewLoc = pHeader->pitem->iOrder - GetHiddenColumnCount();
if(iNewLoc > 0) {
if(m_aColumns[pHeader->iItem].iLocation != iNewLoc) {
if(m_aColumns[pHeader->iItem].iLocation > iNewLoc) {
int iMax = m_aColumns[pHeader->iItem].iLocation;
int iMin = iNewLoc;
for(int i = 0; i < m_iColumnsTracked; i++) {
if(m_aColumns[i].iLocation >= iMin && m_aColumns[i].iLocation < iMax)
m_aColumns[i].iLocation++;
}
}
else if(m_aColumns[pHeader->iItem].iLocation < iNewLoc) {
int iMin = m_aColumns[pHeader->iItem].iLocation;
int iMax = iNewLoc;
for(int i = 0; i < m_iColumnsTracked; i++) {
if(m_aColumns[i].iLocation > iMin && m_aColumns[i].iLocation <= iMax)
m_aColumns[i].iLocation--;
}
}
m_aColumns[pHeader->iItem].iLocation = iNewLoc;
Invalidate(FALSE);
break;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -