📄 comnctrl.cxx
字号:
/*
* comnctrl.cxx
*
* Common control interactor classes implementation.
*
* Portable Windows Library
*
* Copyright (c) 1993-1998 Equivalence Pty. Ltd.
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Portable Windows Library.
*
* The Initial Developer of the Original Code is Equivalence Pty. Ltd.
*
* Portions are Copyright (C) 1993 Free Software Foundation, Inc.
* All Rights Reserved.
*
* Contributor(s): ______________________________________.
*
* $Log: comnctrl.cxx,v $
* Revision 1.5 1999/04/18 14:21:40 robertj
* MSVC 5 backward compatibility
*
* Revision 1.4 1999/02/16 08:08:07 robertj
* MSVC 6.0 compatibility changes.
*
* Revision 1.3 1998/09/24 03:42:34 robertj
* Added open software license.
*
* Revision 1.2 1998/09/22 15:09:14 robertj
* Added OnDraw functions.
*
* Revision 1.1 1998/09/21 14:02:34 robertj
* Initial revision
*
*/
#include <pwlib.h>
#include <commctrl.h>
typedef struct _DllVersionInfo { DWORD cbSize;
DWORD dwMajorVersion; // Major version
DWORD dwMinorVersion; // Minor version
DWORD dwBuildNumber; // Build number
DWORD dwPlatformID; // DLLVER_PLATFORM_*
} DLLVERSIONINFO;
typedef HRESULT (CALLBACK* DLLGETVERSIONPROC)(DLLVERSIONINFO *);
static HRESULT GetComCtlVersion(DWORD & dwMajor, DWORD & dwMinor)
{
//load the DLL
HINSTANCE hComCtl = LoadLibrary(TEXT("comctl32.dll"));
if (hComCtl == NULL)
return E_FAIL;
HRESULT hr = S_OK;
DLLGETVERSIONPROC pDllGetVersion;
/* You must get this function explicitly because earlier versions of the DLL
don't implement this function. That makes the lack of implementation of the
function a version marker in itself. */
pDllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hComCtl, TEXT("DllGetVersion"));
if (pDllGetVersion) {
DLLVERSIONINFO dvi;
ZeroMemory(&dvi, sizeof(dvi));
dvi.cbSize = sizeof(dvi);
hr = (*pDllGetVersion)(&dvi);
if (SUCCEEDED(hr)) {
dwMajor = dvi.dwMajorVersion;
dwMinor = dvi.dwMinorVersion;
}
else {
hr = E_FAIL;
}
}
else {
/* If GetProcAddress failed, then the DLL is a version previous to the one
shipped with IE 3.x. */
dwMajor = 4;
dwMinor = 0;
}
FreeLibrary(hComCtl);
return hr;
}
//////////////////////////////////////////////////////////////////////////////
// PListViewControl
PListViewControl::PListViewControl(PInteractor * parent,
unsigned styles,
PINDEX columnCount,
const char * const * headings)
: PControl(parent, PNotifier(), NULL)
{
DWORD maj, min;
GetComCtlVersion(maj, min);
defaultStyles = styles;
deleteObjects = TRUE;
numColumns = 0;
for (PINDEX col = 0; col < columnCount; col++) {
if (headings != NULL)
InsertColumn(headings[col]);
else
InsertColumn(psprintf("%u", col+1));
}
if (headings != NULL)
SetColumnHeading(0, headings[0]);
SetForegroundColour(parent->GetForegroundColour());
SetBackgroundColour(parent->GetBackgroundColour());
}
void PListViewControl::SetForegroundColour(const PColour & newColour)
{
PControl::SetForegroundColour(newColour);
::SendMessage(GetHWND(), LVM_SETTEXTCOLOR, 0, newColour.ToCOLORREF());
}
void PListViewControl::SetBackgroundColour(const PColour & newColour)
{
PControl::SetBackgroundColour(newColour);
::SendMessage(GetHWND(), LVM_SETBKCOLOR, 0, newColour.ToCOLORREF());
::SendMessage(_hWnd, LVM_SETTEXTBKCOLOR, 0, newColour.ToCOLORREF());
}
void PListViewControl::TransferValue(int option)
{
if (valuePointer != NULL)
if (option == NotifyUpdate)
SetSelection(*(PINDEX *)valuePointer);
else
*(PINDEX *)valuePointer = GetSelection();
}
void PListViewControl::AllowDeleteObjects(BOOL yes)
{
deleteObjects = yes;
}
LRESULT PListViewControl::LVChangeItem(int action,
PListViewItem * obj,
PINDEX index,
BOOL update)
{
SendMessage(GetHWND(), WM_SETREDRAW, update && numColumns == 1, 0L);
LVITEM lv;
lv.iItem = index;
lv.iSubItem = 0;
lv.mask = LVIF_TEXT;
if (obj == NULL)
obj = GetEntry(index);
else {
lv.mask |= LVIF_PARAM;
lv.lParam = (DWORD)obj;
}
PString str = obj->GetColumn(0);
lv.pszText = str.GetPointer();
LRESULT retval = SendMessage(_hWnd, action, 0, (DWORD)&lv);
if (action == LVM_INSERTITEM)
lv.iItem = retval;
lv.mask = LVIF_TEXT;
for (PINDEX col = 1; col < numColumns; col++) {
lv.iSubItem = col;
str = obj->GetColumn(col);
lv.pszText = str.GetPointer();
if (update && col == numColumns - 1)
SendMessage(_hWnd, WM_SETREDRAW, TRUE, 0L);
SendMessage(_hWnd, LVM_SETITEM, 0, (DWORD)&lv);
}
if (!update)
SendMessage(_hWnd, WM_SETREDRAW, TRUE, 0L);
return retval;
}
PINDEX PListViewControl::AddEntry(PListViewItem * obj, BOOL update)
{
if (PAssertNULL(obj) != NULL)
return (PINDEX)LVChangeItem(LVM_INSERTITEM, obj, P_MAX_INDEX, update);
return -1;
}
void PListViewControl::AddEntries(const PCollection & objects, BOOL update)
{
PINDEX last = objects.GetSize() - 1;
for (PINDEX i = 0; i <= last; i++) {
PObject * obj = objects.GetAt(i);
if (obj->IsDescendant(PListViewItem::Class()))
AddEntry((PListViewItem*)obj, update && i < last);
}
}
void PListViewControl::InsertEntry(PListViewItem * obj, PINDEX index, BOOL update)
{
if (PAssertNULL(obj) != NULL)
LVChangeItem(LVM_INSERTITEM, obj, index, update);
}
void PListViewControl::DeleteEntry(PINDEX index, BOOL update)
{
SendMessage(GetHWND(), WM_SETREDRAW, update, 0L);
BOOL doNotify = GetSelection() == index;
SendMessage(_hWnd, LVM_DELETEITEM, index, 0L);
if (!update)
SendMessage(_hWnd, WM_SETREDRAW, TRUE, 0L);
if (doNotify)
parent->OnControlNotify(*this, NewSelection);
}
void PListViewControl::DeleteAllEntries(BOOL update)
{
SendMessage(GetHWND(), WM_SETREDRAW, update, 0L);
BOOL doNotify = GetSelection() != P_MAX_INDEX;
SendMessage(_hWnd, LVM_DELETEALLITEMS, 0, 0L);
if (!update)
SendMessage(_hWnd, WM_SETREDRAW, TRUE, 0L);
if (doNotify)
parent->OnControlNotify(*this, NewSelection);
}
PINDEX PListViewControl::FindEntry(const PListViewItem & obj, PINDEX startIndex) const
{
if (startIndex == P_MAX_INDEX)
startIndex = -1;
PString str = obj.GetColumn(0);
LVFINDINFO lv;
lv.flags = LVFI_STRING;
lv.psz = str.GetPointer();
long retVal = SendMessage(GetHWND(), LVM_FINDITEM, startIndex, (DWORD)&lv);
return retVal != -1 ? (PINDEX)retVal : P_MAX_INDEX;
}
void PListViewControl::UpdateEntry(PINDEX index, BOOL update)
{
LVChangeItem(LVM_SETITEM, NULL, index, update);
}
void PListViewControl::SetEntry(PListViewItem * obj, PINDEX index, BOOL update)
{
BOOL doNotify = GetSelection() == index;
LVChangeItem(LVM_SETITEM, obj, index, update);
if (doNotify)
parent->OnControlNotify(*this, NewSelection);
}
PListViewItem * PListViewControl::GetEntry(PINDEX index) const
{
LVITEM lv;
lv.mask = LVIF_PARAM;
lv.iItem = index;
lv.iSubItem = 0;
long retVal = SendMessage(GetHWND(), LVM_GETITEM, 0, (LPARAM)&lv);
return retVal ? (PListViewItem *)lv.lParam : NULL;
}
PINDEX PListViewControl::GetCount() const
{
return (PINDEX)SendMessage(GetHWND(), LVM_GETITEMCOUNT, 0, 0L);
}
PINDEX PListViewControl::GetTopIndex() const
{
return (PINDEX)SendMessage(GetHWND(), LVM_GETTOPINDEX, 0, 0L);
}
void PListViewControl::InsertColumn(const PString & heading, PINDEX before, BOOL update)
{
SendMessage(GetHWND(), WM_SETREDRAW, update, 0L);
LVCOLUMN lvc;
lvc.mask = LVCF_TEXT | LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM;
lvc.pszText = (LPSTR)(const char *)heading;
lvc.fmt = LVCFMT_LEFT;
lvc.cx = GetStringWidth(heading+" ");
lvc.iSubItem = numColumns++;
SendMessage(_hWnd, LVM_INSERTCOLUMN, before, (DWORD)&lvc);
for (PINDEX entry = 0; entry < GetCount(); entry++) {
LVITEM lv;
lv.mask = LVIF_TEXT|LVCF_SUBITEM;
lv.iItem = entry;
lv.iSubItem = lvc.iSubItem;
PString str = GetEntry(entry)->GetColumn(lvc.iSubItem);
lv.pszText = str.GetPointer();
SendMessage(_hWnd, LVM_SETITEM, 0, (DWORD)&lv);
}
if (!update)
SendMessage(_hWnd, WM_SETREDRAW, TRUE, 0L);
}
void PListViewControl::DeleteColumn(PINDEX column, BOOL update)
{
SendMessage(GetHWND(), WM_SETREDRAW, update, 0L);
SendMessage(_hWnd, LVM_DELETECOLUMN, column, 0);
numColumns--;
if (!update)
SendMessage(_hWnd, WM_SETREDRAW, TRUE, 0L);
}
PINDEX PListViewControl::GetColumnCount()
{
return numColumns;
}
void PListViewControl::SetColumnHeading(PINDEX column, const PString & str)
{
LVCOLUMN lv;
lv.mask = LVCF_TEXT;
lv.pszText = (LPSTR)(const char *)str;
SendMessage(GetHWND(), LVM_SETCOLUMN, column, (DWORD)&lv);
}
PDIMENSION PListViewControl::GetColumnWidth(PINDEX column)
{
return (PDIMENSION)SendMessage(GetHWND(), LVM_GETCOLUMNWIDTH, column, 0L);
}
void PListViewControl::SetColumnWidth(PINDEX column, PDIMENSION newWidth, BOOL update)
{
SendMessage(_hWnd, WM_SETREDRAW, update, 0L);
if (newWidth == 0)
newWidth = (PDIMENSION)LVSCW_AUTOSIZE_USEHEADER;
SendMessage(_hWnd, LVM_SETCOLUMNWIDTH, column, newWidth);
if (!update)
SendMessage(_hWnd, WM_SETREDRAW, TRUE, 0L);
}
PDIMENSION PListViewControl::GetStringWidth(const PString & str)
{
return (PDIMENSION)SendMessage(GetHWND(), LVM_GETSTRINGWIDTH, 0, (DWORD)(const char *)str);
}
void PListViewControl::SetSelection(PINDEX index)
{
PINDEX last = GetCount() - 1;
for (PINDEX entry = 0; entry <= last; entry++)
Select(entry, entry == last, entry == index);
parent->OnControlNotify(*this, NewSelection);
}
PINDEX PListViewControl::GetSelection() const
{
PINDEX last = GetCount() - 1;
for (PINDEX entry = 0; entry <= last; entry++) {
if (IsSelected(entry))
return entry;
}
return P_MAX_INDEX;
}
void PListViewControl::Select(PINDEX index, BOOL update, BOOL sel)
{
SendMessage(GetHWND(), WM_SETREDRAW, update, 0L);
LVITEM lv;
lv.stateMask = LVIS_SELECTED;
lv.state = sel ? LVIS_SELECTED : 0;
SendMessage(_hWnd, LVM_SETITEMSTATE, index, (DWORD)&lv);
if (!update)
SendMessage(_hWnd, WM_SETREDRAW, TRUE, 0L);
}
BOOL PListViewControl::IsSelected(PINDEX index) const
{
return SendMessage(GetHWND(), LVM_GETITEMSTATE, index, LVIS_SELECTED) != 0;
}
PINDEX PListViewControl::GetSelCount() const
{
return (PINDEX)SendMessage(GetHWND(), LVM_GETSELECTEDCOUNT, 0, 0);
}
static int CALLBACK LVCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
PListViewItem * obj1 = (PListViewItem *)lParam1;
PListViewItem * obj2 = (PListViewItem *)lParam2;
return obj1->GetColumn(lParamSort).Compare(obj2->GetColumn(lParamSort));
}
void PListViewControl::OnColumnClick(PINDEX column)
{
SendMessage(GetHWND(), LVM_SORTITEMS, column, (DWORD)LVCompareFunc);
}
void PListViewControl::OnRightClick(PINDEX)
{
}
void PListViewControl::OnBeginDrag(BOOL, PINDEX)
{
}
BOOL PListViewControl::OnDrawControl(PCanvas &, BOOL)
{
return FALSE;
}
BOOL PListViewControl::OnDrawEntry(PINDEX, PINDEX, PListViewItem &, PCanvas &, unsigned)
{
return FALSE;
}
void PListViewControl::GetCreateWinInfo(WNDCLASS & wndClass)
{
PControl::GetCreateWinInfo(wndClass);
wndClass.lpszClassName = WC_LISTVIEW;
if ((defaultStyles&ShowHeadings) == 0)
_styleBits |= LVS_NOCOLUMNHEADER;
if ((defaultStyles&CanHeadingSort) == 0)
_styleBits |= LVS_NOSORTHEADER;
if ((defaultStyles&SingleSelection) != 0)
_styleBits |= LVS_SINGLESEL;
_styleBits |= WS_BORDER|WS_HSCROLL|WS_VSCROLL|LVS_REPORT;
}
int PListViewControl::LVCustomDraw(NMHDR & msg)
{
NMLVCUSTOMDRAW & draw = (NMLVCUSTOMDRAW &)msg;
PDrawCanvas canvas((PListViewControl*)this, draw.nmcd.hdc, FALSE, TRUE);
switch (draw.nmcd.dwDrawStage) {
case CDDS_PREPAINT :
if (OnDrawControl(canvas, FALSE))
return CDRF_NOTIFYPOSTPAINT|CDRF_NOTIFYITEMDRAW;
break;
case CDDS_POSTPAINT :
OnDrawControl(canvas, TRUE);
break;
case CDDS_ITEMPREPAINT :
if (OnDrawEntry(draw.nmcd.dwItemSpec, P_MAX_INDEX,
*(PListViewItem *)draw.nmcd.lItemlParam,
canvas, draw.nmcd.uItemState))
return CDRF_SKIPDEFAULT;
#ifdef CDRF_NOTIFYSUBITEMDRAW
return CDRF_NOTIFYSUBITEMDRAW;
case CDDS_ITEMPREPAINT|CDDS_SUBITEM :
if (OnDrawEntry(draw.nmcd.dwItemSpec, draw.iSubItem,
*(PListViewItem *)draw.nmcd.lItemlParam,
canvas, draw.nmcd.uItemState))
#else
#pragma message("Later version of commctrl.h required!")
#endif
return CDRF_SKIPDEFAULT;
}
draw.clrText = canvas.GetTextFgColour().ToCOLORREF();
draw.clrTextBk = canvas.GetTextBkColour().ToCOLORREF();
return CDRF_DODEFAULT ;
}
int PListViewControl::TranslateOption(NMHDR & msg) const
{
NMLISTVIEW & lv = (NMLISTVIEW &)msg;
switch (msg.code) {
case LVN_DELETEITEM :
delete GetEntry(lv.iItem);
break;
case LVN_ITEMCHANGED :
return NewSelection;
case NM_DBLCLK :
return DoubleClick;
case LVN_BEGINDRAG :
((PListViewControl*)this)->OnBeginDrag(FALSE, lv.iItem);
break;
case LVN_BEGINRDRAG :
((PListViewControl*)this)->OnBeginDrag(TRUE, lv.iItem);
break;
case LVN_COLUMNCLICK :
((PListViewControl*)this)->OnColumnClick(lv.iSubItem);
break;
case NM_RCLICK :
((PListViewControl*)this)->OnRightClick(lv.iItem);
return RightClick;
case NM_CUSTOMDRAW :
_msg->lResult = ((PListViewControl*)this)->LVCustomDraw(msg);
return -2;
}
return -1;
}
void PListViewControl::WndProc()
{
if (_msg->event == WM_DESTROY && deleteObjects) {
for (PINDEX i = 0; i < GetCount(); i++)
delete GetEntry(i);
}
PControl::WndProc();
}
// End Of File ///////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -