2025-11-27 16:46:48 +09:00

1905 lines
43 KiB
C++

// OXListBoxEx.cpp : implementation file
//
// Version: 9.3
#include "stdafx.h"
#include "OXMainRes.h"
#include "OXListBoxEx.h"
#include "UTBStrOp.h"
#include "UTB64Bit.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
BOOL COXListBoxEx::m_bWindowsNTRunning=COXListBoxEx::IsWindowsNTRunning();
IMPLEMENT_DYNAMIC(COXListBoxEx, CListBox)
/////////////////////////////////////////////////////////////////////////////
// COXListBoxEx
COXListBoxEx::COXListBoxEx() :
m_pImageList(NULL),
m_nMaxItemsBeforeSeparator(0),
m_nLastItemBeforeSeparator(-1),
m_nWidestItemIndex(-1),
m_nLastTopIndex(-1),
m_clrBackground(::GetSysColor(COLOR_WINDOW)),
m_bHighlightOnlyText(FALSE),
m_sTooltipText(_T("")),
m_bSaveRestoreMRUState(FALSE)
{
}
COXListBoxEx::~COXListBoxEx()
{
}
BEGIN_MESSAGE_MAP(COXListBoxEx, CListBox)
//{{AFX_MSG_MAP(COXListBoxEx)
ON_WM_CREATE()
ON_WM_ERASEBKGND()
ON_WM_SIZE()
ON_WM_VSCROLL()
ON_WM_SHOWWINDOW()
ON_WM_DESTROY()
ON_WM_MOUSEWHEEL()
ON_WM_CTLCOLOR_REFLECT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// COXListBoxEx message handlers
int COXListBoxEx::CompareItem(LPCOMPAREITEMSTRUCT lpCompareItemStruct)
{
// TODO: Add your code to determine the sorting order of the specified items
// return -1 = item 1 sorts before item 2
// return 0 = item 1 and item 2 sort the same
// return 1 = item 1 sorts after item 2
OXLISTBOXITEM* pLBI1=GetItemInfo(lpCompareItemStruct->itemID1);
if(pLBI1==NULL)
return 0;
OXLISTBOXITEM* pLBI2=GetItemInfo(lpCompareItemStruct->itemID2);
if(pLBI2==NULL)
return 0;
ASSERT(pLBI1->m_nMRUIndex!=pLBI2->m_nMRUIndex ||
(pLBI1->m_nMRUIndex==-1 && pLBI2->m_nMRUIndex==-1));
if(pLBI1->m_nMRUIndex!=pLBI2->m_nMRUIndex)
{
if(pLBI1->m_nMRUIndex==-1)
{
return 1;
}
else if(pLBI2->m_nMRUIndex==-1)
{
return -1;
}
else
{
return ((pLBI1->m_nMRUIndex<pLBI2->m_nMRUIndex ? -1 : 1));
}
}
else
{
return 0;
}
}
void COXListBoxEx::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
// TODO: Add your code to determine the size of specified item
UNREFERENCED_PARAMETER(lpMeasureItemStruct);
}
void COXListBoxEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// TODO: Add your code to draw the specified item
CDC* pDC=CDC::FromHandle(lpDrawItemStruct->hDC);
CRect rect(lpDrawItemStruct->rcItem);
if(GetCount()==0)
{
return;
}
OXLISTBOXITEM* pLBI=NULL;
BOOL bHaveToDelete=FALSE;
if(lpDrawItemStruct->itemID==-1)
{
pLBI=new OXLISTBOXITEM;
bHaveToDelete=TRUE;
}
else
{
pLBI=GetItemInfo(lpDrawItemStruct->itemID);
}
ASSERT(pLBI!=NULL);
CRect rectItem=pLBI->m_rectItem;
CRect rectImage=pLBI->m_rectImage;
CRect rectText=pLBI->m_rectText;
if((int)lpDrawItemStruct->itemID==GetLastItemBeforeSeparator())
{
if((lpDrawItemStruct->itemAction & ODA_DRAWENTIRE))
{
CRect rectSeparator=rect;
rectSeparator.top=rectSeparator.bottom-OXLB_SEPARATOR_HEIGHT;
DrawSeparator(pDC,rectSeparator,pLBI);
}
rect.bottom-=OXLB_SEPARATOR_HEIGHT;
}
rectItem+=rect.TopLeft();
rectImage+=rect.TopLeft();
rectText+=rect.TopLeft();
if((lpDrawItemStruct->itemAction & (ODA_SELECT|ODA_DRAWENTIRE)))
{
CBrush brush(lpDrawItemStruct->itemState & ODS_SELECTED ?
pLBI->m_clrBackgroundHighlight : pLBI->m_clrBackground);
pDC->FillRect((GetHighlightOnlyText() ? rectText : rect),&brush);
}
else if((lpDrawItemStruct->itemAction & (ODA_FOCUS|ODA_DRAWENTIRE)) &&
!(lpDrawItemStruct->itemState & ODS_FOCUS))
{
CBrush brush(lpDrawItemStruct->itemState & ODS_SELECTED ?
pLBI->m_clrBackgroundHighlight : pLBI->m_clrBackground);
pDC->FrameRect((GetHighlightOnlyText() ? rectText : rect),&brush);
}
if(lpDrawItemStruct->itemAction&(ODA_SELECT|ODA_DRAWENTIRE))
{
// draw image
if(!rectImage.IsRectEmpty() && pLBI->m_nImageIndex!=-1)
{
UINT nStyle=(((lpDrawItemStruct->itemState & ODS_SELECTED) &&
GetHighlightOnlyText()) ? ILD_SELECTED : 0) | ILD_TRANSPARENT;
DrawImage(pDC,rectImage,nStyle,pLBI);
}
if(GetStyle()&LBS_HASSTRINGS)
{
// draw text
CString sText;
if(lpDrawItemStruct->itemID==-1)
sText.Empty();
else
GetText(lpDrawItemStruct->itemID,sText);
COLORREF clrText=pLBI->m_clrText;
if(lpDrawItemStruct->itemState & ODS_SELECTED)
clrText=pLBI->m_clrTextHighlight;
DrawText(pDC,sText,rectText,clrText,pLBI->m_pFont);
}
}
if((lpDrawItemStruct->itemAction & (ODA_FOCUS|ODA_DRAWENTIRE)) &&
(lpDrawItemStruct->itemState & ODS_FOCUS))
{
pDC->DrawFocusRect((GetHighlightOnlyText() ? rectText : rect));
}
if(bHaveToDelete)
delete pLBI;
}
void COXListBoxEx::DrawSeparator(CDC* pDC, CRect rectSeparator, OXLISTBOXITEM* pLBI)
{
ASSERT(pDC!=NULL);
ASSERT(pLBI!=NULL);
CBrush brush(pLBI->m_clrBackground);
pDC->FillRect(rectSeparator,&brush);
rectSeparator.top+=OXLB_SEPARATOR_HEIGHT/2-1;
rectSeparator.bottom=rectSeparator.top+2;
::FillRect(pDC->GetSafeHdc(),rectSeparator,
::GetSysColorBrush(COLOR_3DSHADOW));
}
void COXListBoxEx::DrawImage(CDC* pDC, CRect& rectImage,
UINT nStyle, OXLISTBOXITEM* pLBI)
{
ASSERT(pDC!=NULL);
ASSERT(pLBI!=NULL);
ASSERT(GetImageList()!=NULL);
GetImageList()->Draw(pDC,pLBI->m_nImageIndex,rectImage.TopLeft(),nStyle);
}
void COXListBoxEx::DrawText(CDC* pDC, LPCTSTR lpszText, CRect& rectText,
COLORREF clrText, CFont* pFont)
{
ASSERT(pDC!=NULL);
int nOldBkMode=pDC->SetBkMode(TRANSPARENT);
COLORREF clrOldText=pDC->SetTextColor(clrText);
CFont* pOldFont=NULL;
if(pFont!=NULL)
pOldFont=pDC->SelectObject(pFont);
pDC->DrawText(lpszText,rectText,DT_LEFT|DT_SINGLELINE|DT_VCENTER);
if(pOldFont!=NULL)
pDC->SelectObject(pOldFont);
pDC->SetTextColor(clrOldText);
pDC->SetBkMode(nOldBkMode);
}
HBRUSH COXListBoxEx::CtlColor(CDC* pDC, UINT nCtlColor)
{
UNREFERENCED_PARAMETER(pDC);
UNREFERENCED_PARAMETER(nCtlColor);
if(GetCount()==0)
{
static CBrush brush;
if((HBRUSH)brush!=NULL)
brush.DeleteObject();
brush.CreateSolidBrush(m_clrBackground);
return brush;
}
return NULL;
}
void COXListBoxEx::PreSubclassWindow()
{
// TODO: Add your specialized code here and/or call the base class
DWORD dwStyle=GetStyle();
// make sure LBS_OWNERDRAWVARIABLE style is specified
ASSERT(dwStyle&LBS_OWNERDRAWVARIABLE);
_AFX_THREAD_STATE* pThreadState=AfxGetThreadState();
// hook not already in progress
if(pThreadState->m_pWndInit==NULL)
{
if(!InitializeListBox())
{
TRACE(_T("COXListBoxEx::PreSubclassWindow: failed to initialize the control\n"));
}
}
CListBox::PreSubclassWindow();
}
int COXListBoxEx::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CListBox::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
if(!InitializeListBox())
{
TRACE(_T("COXListBoxEx::OnCreate: failed to initialize the control\n"));
return -1;
}
return 0;
}
BOOL COXListBoxEx::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Add your specialized code here and/or call the base class
// make sure LBS_OWNERDRAWVARIABLE style is specified
cs.style&=~LBS_OWNERDRAWFIXED;
cs.style|=LBS_OWNERDRAWVARIABLE;
return CListBox::PreCreateWindow(cs);
}
int COXListBoxEx::DeleteString(UINT nIndex)
{
if(!m_bWindowsNTRunning)
{
int nItemIndex=nIndex;
OXLISTBOXITEM* pLBI=GetItemInfo(nItemIndex);
if(pLBI!=NULL)
{
VERIFY(m_mapItems.RemoveKey(nItemIndex));
delete pLBI;
int nItemCount= PtrToInt(m_mapItems.GetCount());
if(nItemIndex<nItemCount)
{
for(int nIndex=nItemIndex+1; nIndex<=(int)nItemCount; nIndex++)
{
pLBI=GetItemInfo(nIndex);
ASSERT(pLBI!=NULL);
m_mapItems.SetAt(nIndex-1,pLBI);
}
VERIFY(m_mapItems.RemoveKey(nItemCount));
ASSERT(m_mapItems.GetCount()==(int)nItemCount);
}
BOOL bRecalc=(nItemIndex==m_nWidestItemIndex);
if(nItemIndex<=GetLastItemBeforeSeparator())
{
// update MRU list
for(int nIndex=nItemIndex; nIndex<GetLastItemBeforeSeparator(); nIndex++)
{
OXLISTBOXITEM* pLBI=GetItemInfo(nIndex);
ASSERT(pLBI!=NULL);
ASSERT(pLBI->m_nMRUIndex==nIndex+1);
pLBI->m_nMRUIndex--;
}
m_nLastItemBeforeSeparator--;
bRecalc=TRUE;
}
if(bRecalc)
RecalcItemsExtent();
UpdateTooltipTools();
}
else
{
ASSERT(!m_mapItems.Lookup(nItemIndex,pLBI));
}
}
return CListBox::DeleteString(nIndex);
}
void COXListBoxEx::ResetContent()
{
if(!m_bWindowsNTRunning)
{
POSITION pos=m_mapItems.GetStartPosition();
while(pos!=NULL)
{
int nIndex=-1;
OXLISTBOXITEM* pLBI=NULL;
m_mapItems.GetNextAssoc(pos,nIndex,pLBI);
ASSERT(nIndex!=-1);
ASSERT(pLBI!=NULL);
delete pLBI;
}
m_mapItems.RemoveAll();
m_nLastItemBeforeSeparator=-1;
m_nWidestItemIndex=-1;
m_nLastTopIndex=-1;
RecalcItemsExtent();
UpdateTooltipTools();
}
CListBox::ResetContent();
}
void COXListBoxEx::DeleteItem(LPDELETEITEMSTRUCT lpDeleteItemStruct)
{
// TODO: Add your specialized code here and/or call the base class
ASSERT(lpDeleteItemStruct!=NULL);
if(m_bWindowsNTRunning)
{
OXLISTBOXITEM* pLBI=GetItemInfo(lpDeleteItemStruct->itemID);
if(pLBI!=NULL)
{
VERIFY(m_mapItems.RemoveKey(lpDeleteItemStruct->itemID));
delete pLBI;
UINT nItemCount=(UINT)m_mapItems.GetCount();
if(lpDeleteItemStruct->itemID<nItemCount)
{
for(int nIndex=lpDeleteItemStruct->itemID+1;
nIndex<=(int)nItemCount; nIndex++)
{
pLBI=GetItemInfo(nIndex);
ASSERT(pLBI!=NULL);
m_mapItems.SetAt(nIndex-1,pLBI);
}
VERIFY(m_mapItems.RemoveKey(nItemCount));
ASSERT(m_mapItems.GetCount()==(int)nItemCount);
}
CListBox::DeleteItem(lpDeleteItemStruct);
BOOL bRecalc=(lpDeleteItemStruct->itemID==(UINT)m_nWidestItemIndex);
if((int)lpDeleteItemStruct->itemID<=GetLastItemBeforeSeparator())
{
// update MRU list
for(int nIndex=lpDeleteItemStruct->itemID;
nIndex<GetLastItemBeforeSeparator(); nIndex++)
{
OXLISTBOXITEM* pLBI=GetItemInfo(nIndex);
ASSERT(pLBI!=NULL);
ASSERT(pLBI->m_nMRUIndex==nIndex+1);
pLBI->m_nMRUIndex--;
}
m_nLastItemBeforeSeparator--;
bRecalc=TRUE;
}
if(bRecalc)
RecalcItemsExtent();
UpdateTooltipTools();
}
else
{
ASSERT(!m_mapItems.Lookup(lpDeleteItemStruct->itemID,pLBI));
CListBox::DeleteItem(lpDeleteItemStruct);
}
}
else
{
CListBox::DeleteItem(lpDeleteItemStruct);
}
}
BOOL COXListBoxEx::PreTranslateMessage(MSG* pMsg)
{
// TODO: Add your specialized code here and/or call the base class
int nTopIndex=GetTopIndex();
if(nTopIndex!=LB_ERR && nTopIndex!=m_nLastTopIndex)
{
m_nLastTopIndex=nTopIndex;
UpdateTooltipTools();
}
CToolTipCtrl* pTooTipCtrl=GetToolTipCtrl();
ASSERT(pTooTipCtrl!=NULL);
ASSERT(::IsWindow(pTooTipCtrl->GetSafeHwnd()));
pTooTipCtrl->Activate(TRUE);
pTooTipCtrl->RelayEvent(pMsg);
return CListBox::PreTranslateMessage(pMsg);
}
void COXListBoxEx::OnSize(UINT nType, int cx, int cy)
{
CListBox::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
CToolTipCtrl* pTooTipCtrl=GetToolTipCtrl();
ASSERT(pTooTipCtrl!=NULL);
if(::IsWindow(pTooTipCtrl->GetSafeHwnd()))
{
CRect rect;
GetClientRect(rect);
if(rect.IsRectEmpty())
{
rect.right=rect.left+1;
rect.bottom=rect.top+1;
}
CToolInfo toolInfo;
toolInfo.cbSize=sizeof(TOOLINFO);
VERIFY(pTooTipCtrl->GetToolInfo(toolInfo,this,ID_OXLB_TOOLTIP));
toolInfo.rect=rect;
pTooTipCtrl->SetToolInfo(&toolInfo);
}
UpdateTooltipTools();
}
void COXListBoxEx::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// TODO: Add your message handler code here and/or call default
CListBox::OnVScroll(nSBCode, nPos, pScrollBar);
if(nSBCode==SB_ENDSCROLL)
UpdateTooltipTools();
}
BOOL COXListBoxEx::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
CRect rect;
GetClientRect(rect);
if(GetHighlightOnlyText() || GetCount()==0)
{
CBrush brush(m_clrBackground);
pDC->FillRect(rect,&brush);
}
else
{
CRect rectItem;
VERIFY(GetItemRect(GetCount()-1,rectItem)!=LB_ERR);
if(rectItem.bottom<rect.bottom)
{
rect.top=rectItem.bottom;
CBrush brush(m_clrBackground);
pDC->FillRect(rect,&brush);
}
}
return TRUE;
}
void COXListBoxEx::OnShowWindow(BOOL bShow, UINT nStatus)
{
CListBox::OnShowWindow(bShow, nStatus);
// TODO: Add your message handler code here
if(GetExStyle()&WS_EX_TOPMOST)
{
CToolTipCtrl* pTooTipCtrl=GetToolTipCtrl();
ASSERT(pTooTipCtrl!=NULL);
if(::IsWindow(pTooTipCtrl->GetSafeHwnd()))
{
pTooTipCtrl->SetWindowPos(&wndTopMost,0,0,0,0,
SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
}
}
UpdateTooltipTools();
}
void COXListBoxEx::OnDestroy()
{
if(GetSaveRestoreMRUState())
{
SaveMRUState();
}
ResetContent();
if(::IsWindow(m_tooltip.GetSafeHwnd()))
{
VERIFY(m_tooltip.DestroyWindow());
}
CListBox::OnDestroy();
}
OXLISTBOXITEM* COXListBoxEx::GetItemInfo(int nIndex) const
{
OXLISTBOXITEM* pLBI=NULL;
if(!m_mapItems.Lookup(nIndex,pLBI))
{
return NULL;
}
else
{
ASSERT(pLBI!=NULL);
return pLBI;
}
}
CFont* COXListBoxEx::GetItemFont(int nIndex) const
{
OXLISTBOXITEM* pLBI=GetItemInfo(nIndex);
if(pLBI==NULL)
return NULL;
else
return pLBI->m_pFont;
}
COLORREF COXListBoxEx::GetItemTextColor(int nIndex) const
{
OXLISTBOXITEM* pLBI=GetItemInfo(nIndex);
if(pLBI==NULL)
return CLR_NONE;
else
return pLBI->m_clrText;
}
COLORREF COXListBoxEx::GetItemTextColorHighlight(int nIndex) const
{
OXLISTBOXITEM* pLBI=GetItemInfo(nIndex);
if(pLBI==NULL)
return CLR_NONE;
else
return pLBI->m_clrTextHighlight;
}
COLORREF COXListBoxEx::GetItemBkColor(int nIndex) const
{
OXLISTBOXITEM* pLBI=GetItemInfo(nIndex);
if(pLBI==NULL)
return CLR_NONE;
else
return pLBI->m_clrBackground;
}
COLORREF COXListBoxEx::GetItemBkColorHighlight(int nIndex) const
{
OXLISTBOXITEM* pLBI=GetItemInfo(nIndex);
if(pLBI==NULL)
return CLR_NONE;
else
return pLBI->m_clrBackgroundHighlight;
}
int COXListBoxEx::GetItemImageIndex(int nIndex) const
{
OXLISTBOXITEM* pLBI=GetItemInfo(nIndex);
if(pLBI==NULL)
return -1;
else
return pLBI->m_nImageIndex;
}
int COXListBoxEx::GetItemIndent(int nIndex) const
{
OXLISTBOXITEM* pLBI=GetItemInfo(nIndex);
if(pLBI==NULL)
return 0;
else
return pLBI->m_nIndent;
}
CString COXListBoxEx::GetItemTooltipText(int nIndex) const
{
OXLISTBOXITEM* pLBI=GetItemInfo(nIndex);
if(pLBI==NULL)
return _T("");
else
return pLBI->m_sTooltipText;
}
BOOL COXListBoxEx::SetItemInfo(int nIndex, int nMask, OXLISTBOXITEM* pLBI)
{
ASSERT(pLBI!=NULL);
return SetItemInfo(nIndex,nMask,pLBI->m_pFont,pLBI->m_clrText,
pLBI->m_clrBackground,pLBI->m_sTooltipText,pLBI->m_nImageIndex,
pLBI->m_nIndent,pLBI->m_clrTextHighlight,pLBI->m_clrBackgroundHighlight);
}
BOOL COXListBoxEx::SetItemInfo(int nIndex, int nMask/*=0*/, CFont* pFont/*=NULL*/,
COLORREF clrText/*=::GetSysColor(COLOR_WINDOWTEXT)*/,
COLORREF clrBackground/*=::GetSysColor(COLOR_WINDOW)*/,
CString sTooltipText/*=_T("")*/,
int nImageIndex/*=-1*/, int nIndent/*=0*/,
COLORREF clrTextHighlight/*=::GetSysColor(COLOR_HIGHLIGHTTEXT)*/,
COLORREF clrBackgroundHighlight/*=::GetSysColor(COLOR_HIGHLIGHT)*/)
{
if(nIndex<-1 && nIndex>=GetCount())
return FALSE;
if(nIndex==-1)
{
for(int nItemIndex=0; nItemIndex<GetCount(); nItemIndex++)
{
VERIFY(SetItemInfo(nItemIndex,nMask,pFont,clrText,
clrBackground,sTooltipText,nImageIndex,nIndent,
clrTextHighlight,clrBackgroundHighlight));
}
return TRUE;
}
OXLISTBOXITEM* pLBI=GetItemInfo(nIndex);
if(pLBI==NULL)
{
pLBI=new OXLISTBOXITEM(pFont,clrText,clrBackground,sTooltipText,
nImageIndex,nIndent,clrTextHighlight,clrBackgroundHighlight);
m_mapItems.SetAt(nIndex,pLBI);
RecalcItemsExtent(nIndex);
UpdateTooltipTools();
}
else
{
if(nMask&OXLBI_FONT)
pLBI->m_pFont=pFont;
if(nMask&OXLBI_TEXTCOLOR)
pLBI->m_clrText=clrText;
if(nMask&OXLBI_BKCOLOR)
pLBI->m_clrBackground=clrBackground;
if(nMask&OXLBI_TOOLTIPTEXT)
pLBI->m_sTooltipText=sTooltipText;
if(nMask&OXLBI_IMAGEINDEX)
pLBI->m_nImageIndex=nImageIndex;
if(nMask&OXLBI_INDENT)
pLBI->m_nIndent=nIndent;
if(nMask&OXLBI_TEXTCOLORHIGHLIGHT)
pLBI->m_clrTextHighlight=clrTextHighlight;
if(nMask&OXLBI_BKCOLORHIGHLIGHT)
pLBI->m_clrBackgroundHighlight=clrBackgroundHighlight;
if(nMask&OXLBI_FONT || nMask&OXLBI_INDENT)
{
RecalcItemsExtent(nIndex);
}
if(nMask&OXLBI_FONT || nMask&OXLBI_INDENT || nMask&OXLBI_TOOLTIPTEXT)
{
UpdateTooltipTools();
}
}
CRect rect;
GetClientRect(rect);
CRect rectItem;
VERIFY(GetItemRect(nIndex,rectItem)!=LB_ERR);
if(rectItem.IntersectRect(rectItem,rect))
RedrawWindow();
return TRUE;
}
BOOL COXListBoxEx::SetItemFont(int nIndex, CFont* pFont)
{
return SetItemInfo(nIndex,OXLBI_FONT,pFont);
}
BOOL COXListBoxEx::SetItemTextColor(int nIndex, COLORREF clrText)
{
return SetItemInfo(nIndex,OXLBI_TEXTCOLOR,NULL,clrText);
}
BOOL COXListBoxEx::SetItemTextColorHighlight(int nIndex, COLORREF clrTextHighlight)
{
OXLISTBOXITEM lbi;
lbi.m_clrTextHighlight=clrTextHighlight;
return SetItemInfo(nIndex,OXLBI_TEXTCOLORHIGHLIGHT,&lbi);
}
BOOL COXListBoxEx::SetItemBkColor(int nIndex, COLORREF clrBackground)
{
return SetItemInfo(nIndex,OXLBI_BKCOLOR,NULL,::GetSysColor(COLOR_WINDOWTEXT),
clrBackground);
}
BOOL COXListBoxEx::SetItemBkColorHighlight(int nIndex, COLORREF clrBackgroundHighlight)
{
OXLISTBOXITEM lbi;
lbi.m_clrBackgroundHighlight=clrBackgroundHighlight;
return SetItemInfo(nIndex,OXLBI_BKCOLORHIGHLIGHT,&lbi);
}
BOOL COXListBoxEx::SetItemImageIndex(int nIndex, int nImageIndex)
{
return SetItemInfo(nIndex,OXLBI_IMAGEINDEX,NULL,::GetSysColor(COLOR_WINDOWTEXT),
::GetSysColor(COLOR_WINDOW),_T(""),nImageIndex);
}
BOOL COXListBoxEx::SetItemIndent(int nIndex, int nIndent)
{
return SetItemInfo(nIndex,OXLBI_INDENT,NULL,::GetSysColor(COLOR_WINDOWTEXT),
::GetSysColor(COLOR_WINDOW),_T(""),-1,nIndent);
}
BOOL COXListBoxEx::SetItemTooltipText(int nIndex, CString sTooltipText)
{
return SetItemInfo(nIndex,OXLBI_TOOLTIPTEXT,NULL,::GetSysColor(COLOR_WINDOWTEXT),
::GetSysColor(COLOR_WINDOW),sTooltipText);
}
int COXListBoxEx::AddString(LPCTSTR lpszItem, int nMask, OXLISTBOXITEM* pLBI)
{
ASSERT(pLBI!=NULL);
return AddString(lpszItem,nMask,pLBI->m_pFont,pLBI->m_clrText,
pLBI->m_clrBackground,pLBI->m_sTooltipText,pLBI->m_nImageIndex,
pLBI->m_nIndent,pLBI->m_clrTextHighlight,pLBI->m_clrBackgroundHighlight);
}
int COXListBoxEx::AddString(LPCTSTR lpszItem, int nMask/*=0*/, CFont* pFont/*=NULL*/,
COLORREF clrText/*=::GetSysColor(COLOR_WINDOWTEXT)*/,
COLORREF clrBackground/*=::GetSysColor(COLOR_WINDOW)*/,
CString sTooltipText/*=_T("")*/,
int nImageIndex/*=-1*/, int nIndent/*=0*/,
COLORREF clrTextHighlight/*=::GetSysColor(COLOR_HIGHLIGHTTEXT)*/,
COLORREF clrBackgroundHighlight/*=::GetSysColor(COLOR_HIGHLIGHT)*/)
{
int nResult=CListBox::AddString(lpszItem);
if(nResult>=0)
{
const int nItemCount = PtrToInt(m_mapItems.GetCount());
// If we didn't insert at the end, then the box is sorted, and we need to
// move the item info objects to line up with the new order.
if (nResult != nItemCount)
{
for(int nIndexUpdate=nItemCount-1;
nIndexUpdate>=nResult; nIndexUpdate--)
{
OXLISTBOXITEM* pLBI=GetItemInfo(nIndexUpdate);
ASSERT(pLBI!=NULL);
m_mapItems.SetAt(nIndexUpdate+1,pLBI);
}
m_mapItems.RemoveKey(nResult);
}
ASSERT(nItemCount == m_mapItems.GetCount());
SetItemInfo(nResult,nMask,pFont,clrText,clrBackground,sTooltipText,
nImageIndex,nIndent,clrTextHighlight,clrBackgroundHighlight);
}
return nResult;
}
int COXListBoxEx::InsertString(int nIndex, LPCTSTR lpszItem, int nMask,
OXLISTBOXITEM* pLBI)
{
ASSERT(pLBI!=NULL);
return InsertString(nIndex,lpszItem,nMask,pLBI->m_pFont,pLBI->m_clrText,
pLBI->m_clrBackground,pLBI->m_sTooltipText,pLBI->m_nImageIndex,
pLBI->m_nIndent,pLBI->m_clrTextHighlight,pLBI->m_clrBackgroundHighlight);
}
int COXListBoxEx::InsertString(int nIndex, LPCTSTR lpszItem,
int nMask/*=0*/, CFont* pFont/*=NULL*/,
COLORREF clrText/*=::GetSysColor(COLOR_WINDOWTEXT)*/,
COLORREF clrBackground/*=::GetSysColor(COLOR_WINDOW)*/,
CString sTooltipText/*=_T("")*/,
int nImageIndex/*=-1*/, int nIndent/*=0*/,
COLORREF clrTextHighlight/*=::GetSysColor(COLOR_HIGHLIGHTTEXT)*/,
COLORREF clrBackgroundHighlight/*=::GetSysColor(COLOR_HIGHLIGHT)*/)
{
if(nIndex==-1)
{
return AddString(lpszItem,nMask,pFont,clrText,clrBackground,
sTooltipText,nImageIndex,nIndent,clrTextHighlight,clrBackgroundHighlight);
}
int nResult=CListBox::InsertString(nIndex,lpszItem);
if(nResult==nIndex)
{
int nItemCount= PtrToInt(m_mapItems.GetCount());
if(nIndex<nItemCount)
{
for(int nIndexUpdate=nItemCount-1;
nIndexUpdate>=nIndex; nIndexUpdate--)
{
OXLISTBOXITEM* pLBI=GetItemInfo(nIndexUpdate);
ASSERT(pLBI!=NULL);
m_mapItems.SetAt(nIndexUpdate+1,pLBI);
}
m_mapItems.RemoveKey(nIndex);
}
ASSERT(nItemCount==m_mapItems.GetCount());
SetItemInfo(nIndex,nMask,pFont,clrText,clrBackground,sTooltipText,
nImageIndex,nIndent,clrTextHighlight,clrBackgroundHighlight);
}
return nResult;
}
void COXListBoxEx::SetMaxItemsBeforeSeparator(int nMaxItemsBeforeSeparator)
{
ASSERT(nMaxItemsBeforeSeparator>=-1);
m_nMaxItemsBeforeSeparator=nMaxItemsBeforeSeparator;
if(m_nMaxItemsBeforeSeparator!=-1 &&
m_nMaxItemsBeforeSeparator<=GetLastItemBeforeSeparator())
{
for(int nIndex=GetLastItemBeforeSeparator();
nIndex>=m_nMaxItemsBeforeSeparator; nIndex--)
{
VERIFY(MRUDelete(nIndex)!=LB_ERR);
}
m_nLastItemBeforeSeparator=m_nMaxItemsBeforeSeparator-1;
if(::IsWindow(GetSafeHwnd()))
{
RecalcItemsExtent();
UpdateTooltipTools();
RedrawWindow();
}
}
}
void COXListBoxEx::RecalcItemsExtent(int nItemIndex/*=-1*/)
{
if(nItemIndex==-1)
{
for(int nIndex=0; nIndex<m_mapItems.GetCount(); nIndex++)
{
RecalcItemsExtent(nIndex);
}
}
else
{
int nMaxLength=GetHorizontalExtent();
CRect rectItem;
CRect rectItemVisible;
CRect rectImage;
CRect rectText;
CalcItemRects(nItemIndex,rectItem,rectItemVisible,rectImage,rectText);
VERIFY(SetItemHeight(nItemIndex,rectItem.Height())!=LB_ERR);
if(rectItem.Width()>nMaxLength)
{
m_nWidestItemIndex=nItemIndex;
nMaxLength=rectItem.Width();
SetHorizontalExtent(nMaxLength);
}
}
}
void COXListBoxEx::CalcItemRects(int nIndex, CRect& rectItem,
CRect& rectItemVisible, CRect& rectImage,
CRect& rectText)
{
ASSERT(nIndex>=0 && nIndex<GetCount());
rectItem.SetRectEmpty();
rectItemVisible.SetRectEmpty();
rectImage.SetRectEmpty();
rectText.SetRectEmpty();
OXLISTBOXITEM* pLBI=GetItemInfo(nIndex);
ASSERT(pLBI!=NULL);
int nWidthText=0;
int nHeightText=0;
int nWidthImage=0;
int nHeightImage=0;
// calculating image size
CalcImageSize(nIndex,nWidthImage,nHeightImage);
// calculating text size
CalcTextSize(nIndex,nWidthText,nHeightText);
// combining two rects
rectItem.right=pLBI->m_nIndent+(nWidthImage>0 ? OXLB_IMAGEOFFSET_X : 0)+
nWidthImage+2*OXLB_TEXTOFFSET_X+nWidthText;
if(nHeightImage+2*OXLB_IMAGEOFFSET_Y>nHeightText+2*OXLB_TEXTOFFSET_Y)
{
rectItem.bottom=nHeightImage+2*OXLB_IMAGEOFFSET_Y;
}
else
{
rectItem.bottom=nHeightText+2*OXLB_TEXTOFFSET_Y;
}
if(nWidthImage>0)
{
rectImage.left=pLBI->m_nIndent+OXLB_IMAGEOFFSET_X;
rectImage.top=(rectItem.Height()-nHeightImage)/2;
rectImage.right=rectImage.left+nWidthImage;
rectImage.bottom=rectImage.top+nHeightImage;
}
rectText.left=pLBI->m_nIndent+(nWidthImage>0 ? OXLB_IMAGEOFFSET_X : 0)+
nWidthImage+OXLB_TEXTOFFSET_X;
rectText.top=(rectItem.Height()-nHeightText)/2;
rectText.right=rectText.left+nWidthText;
rectText.bottom=rectText.top+nHeightText;
if(nIndex==GetLastItemBeforeSeparator())
rectItem.bottom+=OXLB_SEPARATOR_HEIGHT;
rectItemVisible=rectItem;
CRect rect;
GetClientRect(rect);
if(rect.Width()<rectItemVisible.Width())
rectItemVisible.right=rect.Width();
pLBI->m_rectItem=rectItem;
pLBI->m_rectImage=rectImage;
pLBI->m_rectText=rectText;
}
void COXListBoxEx::CalcImageSize(int nIndex, int& nWidthImage, int& nHeightImage)
{
UNREFERENCED_PARAMETER(nIndex);
if(GetImageList()!=NULL && GetImageList()->GetImageCount()>0)
{
IMAGEINFO imageInfo;
VERIFY(GetImageList()->GetImageInfo(0,&imageInfo));
CRect rectImage=imageInfo.rcImage;
nWidthImage=rectImage.Width();
nHeightImage=rectImage.Height();
}
else
{
nWidthImage=0;
nHeightImage=0;
}
}
void COXListBoxEx::CalcTextSize(int nIndex, int& nWidthText, int& nHeightText)
{
if(GetStyle()&LBS_HASSTRINGS)
{
OXLISTBOXITEM* pLBI=GetItemInfo(nIndex);
ASSERT(pLBI!=NULL);
CString sText;
GetText(nIndex,sText);
CClientDC dc(this);
CFont* pOldFont=NULL;
if(pLBI->m_pFont!=NULL)
pOldFont=dc.SelectObject(pLBI->m_pFont);
CRect rectText(0, 0, 0, 0);
dc.DrawText(sText,rectText,DT_CALCRECT|DT_LEFT|DT_SINGLELINE);
if(pOldFont!=NULL)
dc.SelectObject(pOldFont);
nWidthText=rectText.Width();
nHeightText=rectText.Height();
}
else
{
nWidthText=0;
nHeightText=0;
}
}
void COXListBoxEx::RecalcLayout()
{
if(::IsWindow(GetSafeHwnd()))
{
RecalcItemsExtent();
UpdateTooltipTools();
}
}
BOOL COXListBoxEx::InitializeListBox()
{
ASSERT(::IsWindow(GetSafeHwnd()));
ASSERT(GetCount()==0);
CToolTipCtrl* pTooTipCtrl=GetToolTipCtrl();
ASSERT(pTooTipCtrl!=NULL);
ASSERT(!::IsWindow(pTooTipCtrl->GetSafeHwnd()));
BOOL bIsTopMost=(GetExStyle()&WS_EX_TOPMOST);
pTooTipCtrl->Create(this,(bIsTopMost ? TTS_ALWAYSTIP : 0));
// make sure tooltip window is displayed even in the case when
// list box is popup window
if(bIsTopMost)
{
pTooTipCtrl->SetWindowPos(&wndTopMost,0,0,0,0,
SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
}
CRect rect;
GetClientRect(rect);
if(rect.IsRectEmpty())
{
rect.right=rect.left+1;
rect.bottom=rect.top+1;
}
pTooTipCtrl->AddTool(this,GetTooltipText(),rect,ID_OXLB_TOOLTIP);
UpdateTooltipTools();
return TRUE;
}
void COXListBoxEx::UpdateTooltipTools()
{
ASSERT(::IsWindow(GetSafeHwnd()));
// set up tool areas
CToolTipCtrl* pTooTipCtrl=GetToolTipCtrl();
ASSERT(pTooTipCtrl!=NULL);
if(::IsWindow(pTooTipCtrl->GetSafeHwnd()))
{
// delete all existing tools
int nToolCount=pTooTipCtrl->GetToolCount();
for(int nIndex=1; nIndex<nToolCount; nIndex++)
{
pTooTipCtrl->DelTool(this,nIndex);
}
ASSERT(pTooTipCtrl->GetToolCount()==1);
// now add new tools
CRect rect;
GetClientRect(rect);
int nTopItemIndex=GetTopIndex();
if(nTopItemIndex>=0)
{
CRect lineRect=rect;
lineRect.bottom=GetItemHeight(nTopItemIndex);
int nTooltipIndex=1;
for(int nIndex=nTopItemIndex; nIndex<m_mapItems.GetCount(); nIndex++)
{
OXLISTBOXITEM* pLBI=GetItemInfo(nIndex);
ASSERT(pLBI!=NULL);
if(!pLBI->m_sTooltipText.IsEmpty())
{
if(GetHighlightOnlyText())
{
if(lineRect.left<pLBI->m_rectImage.left)
lineRect.left=pLBI->m_rectImage.left;
else if(lineRect.left<pLBI->m_rectText.left)
lineRect.left=pLBI->m_rectText.left;
if(lineRect.right>pLBI->m_rectText.right)
lineRect.right=pLBI->m_rectText.right;
}
VERIFY(pTooTipCtrl->AddTool(this,pLBI->m_sTooltipText,
lineRect,nTooltipIndex));
nTooltipIndex++;
}
lineRect.top=lineRect.bottom;
if(lineRect.top>=rect.bottom)
break;
lineRect.bottom=lineRect.top+GetItemHeight(nIndex+1);
}
}
}
}
int COXListBoxEx::MRUInsert(int nItemIndex, int nMRUIndex,
BOOL bForceToInsert/*=TRUE*/)
{
ASSERT(GetMaxItemsBeforeSeparator()==-1 ||
GetLastItemBeforeSeparator()+1<=GetMaxItemsBeforeSeparator());
if(nItemIndex<0 || nItemIndex>=GetCount())
{
TRACE(_T("COXListBoxEx::MRUInsert: failed to move to MRU list - the item is not found\n"));
return LB_ERR;
}
if(nMRUIndex<0 || nMRUIndex>GetLastItemBeforeSeparator()+1 ||
(GetMaxItemsBeforeSeparator()!=-1 && nMRUIndex>GetMaxItemsBeforeSeparator()))
{
TRACE(_T("COXListBoxEx::MRUInsert: failed to move to MRU list - invalid MRU index has been specified\n"));
return LB_ERR;
}
if(!bForceToInsert && GetMaxItemsBeforeSeparator()!=-1 &&
GetLastItemBeforeSeparator()+1==GetMaxItemsBeforeSeparator() &&
nItemIndex>GetLastItemBeforeSeparator())
{
TRACE(_T("COXListBoxEx::MRUInsert: failed to move to MRU list - the max number of MRU items has been reached\n"));
return LB_ERR;
}
if(GetLastItemBeforeSeparator()+1==GetMaxItemsBeforeSeparator() &&
nItemIndex>GetLastItemBeforeSeparator())
{
ASSERT(bForceToInsert);
int nNewIndex=MRUDelete(GetLastItemBeforeSeparator());
if(nNewIndex==LB_ERR)
return LB_ERR;
if(nItemIndex<=nNewIndex && nItemIndex>GetLastItemBeforeSeparator())
nItemIndex--;
}
// preserve the data associated with the item
OXLISTBOXITEM* pLBI=GetItemInfo(nItemIndex);
ASSERT(pLBI!=NULL);
if(nItemIndex==nMRUIndex)
{
if(pLBI->m_nMRUIndex>=0)
{
ASSERT(pLBI->m_nMRUIndex==nItemIndex);
}
else
{
ASSERT(GetLastItemBeforeSeparator()+1==nItemIndex);
pLBI->m_nMRUIndex=nItemIndex;
m_nLastItemBeforeSeparator++;
RecalcItemsExtent();
UpdateTooltipTools();
}
return nMRUIndex;
}
OXLISTBOXITEM lbiCopy=*pLBI;
CString sText;
GetText(nItemIndex,sText);
DWORD_PTR dwData=GetItemData(nItemIndex);
BOOL bIsSelected=FALSE;
BOOL bIsFocus=FALSE;
BOOL bIsMultipleSel=(GetStyle()&LBS_MULTIPLESEL);
if(bIsMultipleSel)
{
bIsSelected=GetSel(nItemIndex);
bIsFocus=(GetCaretIndex()==nItemIndex);
}
else
{
bIsSelected=(GetCurSel()==nItemIndex);
bIsFocus=bIsSelected;
}
// delete item
VERIFY(DeleteString(nItemIndex)!=LB_ERR);
// update MRU list
for(int nIndex=nMRUIndex; nIndex<=GetLastItemBeforeSeparator(); nIndex++)
{
OXLISTBOXITEM* pLBI=GetItemInfo(nIndex);
ASSERT(pLBI!=NULL);
ASSERT(pLBI->m_nMRUIndex==nIndex);
pLBI->m_nMRUIndex++;
}
m_nLastItemBeforeSeparator++;
// insert item
VERIFY(InsertString(nMRUIndex,sText,OXLBI_ALL,&lbiCopy)==nMRUIndex);
pLBI=GetItemInfo(nMRUIndex);
ASSERT(pLBI!=NULL);
pLBI->m_nMRUIndex=nMRUIndex;
// restore data
VERIFY(SetItemData(nMRUIndex,dwData)!=LB_ERR);
if(bIsMultipleSel)
{
if(bIsSelected)
VERIFY(SetSel(nMRUIndex,TRUE)!=LB_ERR);
if(bIsFocus)
VERIFY(SetCaretIndex(nMRUIndex,TRUE)!=LB_ERR);
}
else
{
if(bIsSelected)
VERIFY(SetCurSel(nMRUIndex)!=LB_ERR);
}
RecalcItemsExtent();
UpdateTooltipTools();
return nMRUIndex;
}
int COXListBoxEx::MRUDelete(int nMRUIndex)
{
if(nMRUIndex<0 || nMRUIndex>GetLastItemBeforeSeparator())
{
TRACE(_T("COXListBoxEx::MRUDelete: failed to delete from MRU list - invalid MRU index has been specified\n"));
return LB_ERR;
}
// preserve the data associated with the item
OXLISTBOXITEM* pLBI=GetItemInfo(nMRUIndex);
ASSERT(pLBI!=NULL);
OXLISTBOXITEM lbiCopy=*pLBI;
ASSERT(lbiCopy.m_nMRUIndex==nMRUIndex);
CString sText;
GetText(nMRUIndex,sText);
DWORD_PTR dwData=GetItemData(nMRUIndex);
BOOL bIsSelected=FALSE;
BOOL bIsFocus=FALSE;
BOOL bIsMultipleSel=(GetStyle()&LBS_MULTIPLESEL);
if(bIsMultipleSel)
{
bIsSelected=GetSel(nMRUIndex);
bIsFocus=(GetCaretIndex()==nMRUIndex);
}
else
{
bIsSelected=(GetCurSel()==nMRUIndex);
bIsFocus=bIsSelected;
}
// delete item
VERIFY(DeleteString(nMRUIndex)!=LB_ERR);
// insert item
int nItemIndex=AddFormerMRUString(sText,OXLBI_ALL,&lbiCopy);
ASSERT(nItemIndex!=LB_ERR);
pLBI=GetItemInfo(nItemIndex);
ASSERT(pLBI!=NULL);
pLBI->m_nMRUIndex=-1;
// restore data
VERIFY(SetItemData(nItemIndex,dwData)!=LB_ERR);
if(bIsMultipleSel)
{
if(bIsSelected)
VERIFY(SetSel(nItemIndex,TRUE)!=LB_ERR);
if(bIsFocus)
VERIFY(SetCaretIndex(nItemIndex,TRUE)!=LB_ERR);
}
else
{
if(bIsSelected)
VERIFY(SetCurSel(nItemIndex)!=LB_ERR);
}
return nItemIndex;
}
BOOL COXListBoxEx::RestoreMRUState(LPCTSTR lpszSectionName/*=_T("OXLISTBOXEX_MRU")*/)
{
ASSERT(::IsWindow(GetSafeHwnd()));
CString sSectionName=lpszSectionName;
ASSERT(!sSectionName.IsEmpty());
// restore MRU list
CWinApp* pApp=AfxGetApp();
ASSERT(pApp!=NULL);
int nMaxItemsBeforeSeparator=pApp->GetProfileInt(sSectionName,
_T("MRU_MaxNumber"),GetMaxItemsBeforeSeparator());
SetMaxItemsBeforeSeparator(nMaxItemsBeforeSeparator);
int nCount=pApp->GetProfileInt(sSectionName,_T("MRU_Count"),
nMaxItemsBeforeSeparator);
ASSERT(nCount<=nMaxItemsBeforeSeparator || nMaxItemsBeforeSeparator==-1);
int nIndex=0;
for(nIndex=GetLastItemBeforeSeparator(); nIndex>=0; nIndex--)
{
VERIFY(MRUDelete(nIndex)!=LB_ERR);
}
for(nIndex=0; nIndex<nCount; nIndex++)
{
CString sEntryName;
sEntryName.Format(_T("MRU_Entry_%d"),nIndex);
CString sText=pApp->GetProfileString(sSectionName,sEntryName,_T(""));
if(!sText.IsEmpty())
{
int nFoundIndex=FindStringExact(-1,sText);
if(nFoundIndex!=LB_ERR)
{
VERIFY(MRUAdd(nFoundIndex)!=LB_ERR);
}
}
else
{
break;
}
}
return TRUE;
}
BOOL COXListBoxEx::SaveMRUState(LPCTSTR lpszSectionName/*=_T("OXLISTBOXEX_MRU")*/)
{
ASSERT(::IsWindow(GetSafeHwnd()));
CString sSectionName=lpszSectionName;
ASSERT(!sSectionName.IsEmpty());
// save MRU list
CWinApp* pApp=AfxGetApp();
ASSERT(pApp!=NULL);
pApp->WriteProfileInt(sSectionName,_T("MRU_MaxNumber"),
GetMaxItemsBeforeSeparator());
pApp->WriteProfileInt(sSectionName,_T("MRU_Count"),
GetLastItemBeforeSeparator()+1);
for(int nIndex=0; nIndex<=GetLastItemBeforeSeparator(); nIndex++)
{
CString sEntryName;
sEntryName.Format(_T("MRU_Entry_%d"),nIndex);
CString sText;
GetText(nIndex,sText);
ASSERT(!sText.IsEmpty());
pApp->WriteProfileString(sSectionName,sEntryName,sText);
}
return TRUE;
}
BOOL COXListBoxEx::IsWindowsNTRunning()
{
BOOL bResult=FALSE;
OSVERSIONINFO verInfo;
verInfo.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
if (::GetVersionEx(&verInfo))
{
if (verInfo.dwPlatformId==VER_PLATFORM_WIN32_NT &&
verInfo.dwMajorVersion>=4)
{
bResult=TRUE;
}
}
return bResult;
}
BOOL COXListBoxEx::OnMouseWheel( UINT /*nFlags*/, short zDelta, CPoint /*pt*/ )
{
if ( zDelta > 0 )
SetTopIndex( GetTopIndex() - 1 );
else
SetTopIndex( GetTopIndex() + 1 );
return TRUE;
}
///////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
int FontEntrySortFunc(const void* pFont1, const void* pFont2)
{
ASSERT(pFont1!=NULL);
ASSERT(pFont2!=NULL);
OXLBFONTINFO* pFontInfo1=(OXLBFONTINFO*)pFont1;
OXLBFONTINFO* pFontInfo2=(OXLBFONTINFO*)pFont2;
return _tcsicmp(pFontInfo1->m_lf.lfFaceName,pFontInfo2->m_lf.lfFaceName);
}
//////////////////////////////////////////////////////////////////////////////
int CALLBACK FontListBoxEnumFontProc(const LOGFONT* pLF, const TEXTMETRIC* pTM,
DWORD dwFontType, LPARAM lParam)
{
#if defined (_WINDLL)
#if defined (_AFXDLL)
AFX_MANAGE_STATE(AfxGetAppModuleState());
#else
AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif
#endif
UNREFERENCED_PARAMETER(pTM);
ASSERT(lParam!=NULL);
COXFontListBox* pFontListBox=(COXFontListBox*)lParam;
OXLBFONTINFO newFont;
newFont.m_lf=*pLF;
newFont.m_bIsSymbol=FALSE;
newFont.m_dwType=dwFontType;
newFont.m_lf.lfHeight=pFontListBox->GetFontHeight();
newFont.m_lf.lfWidth=0;
TCHAR fontName[sizeof(pLF->lfFaceName)/sizeof(TCHAR)];
UTBStr::tcscpy(fontName, sizeof(pLF->lfFaceName)/sizeof(TCHAR), pLF->lfFaceName);
#if _MSC_VER >= 1400
if (fontName[0] != 0)
_tcsupr_s(fontName, _tcslen(fontName)+1);
#else
if (fontName[0] != 0)
_tcsupr(fontName);
#endif
// check if likely to be a symbol font
if (pLF->lfCharSet==SYMBOL_CHARSET ||
_tcsstr(fontName,_T("SYMBOL"))!=NULL ||
_tcsstr(fontName,_T("BATS"))!=NULL ||
_tcsstr(fontName,_T("BRAILLE"))!=NULL ||
_tcsstr(fontName,_T(" EXTRAS"))!=NULL ||
(_tcsstr(fontName,_T("LINE"))!=NULL &&
_tcsstr (fontName, _T("DRAW"))!=NULL) ||
_tcsstr(fontName,_T("SYMBOL "))!=NULL)
{
newFont.m_bIsSymbol=TRUE;
}
if(pFontListBox->FilterFont(&newFont))
{
pFontListBox->m_arrFonts.Add(newFont);
}
return 1;
}
IMPLEMENT_DYNAMIC(COXFontListBox, COXListBoxEx)
/////////////////////////////////////////////////////////////////////////////
COXFontListBox::COXFontListBox() :
m_nFontHeight(OXLBF_DEFAULTFONTHEIGHT),
m_dc(NULL),
m_dcScreen(NULL)
{
VERIFY(m_ilFontIcons.Create(IDB_OX_IL_FONTTYPE,16,0,RGB(192,192,192)));
SetImageList(&m_ilFontIcons);
SetMaxItemsBeforeSeparator(OXLBF_DEFAULTMAXNUMBEFORESEPARATOR);
}
COXFontListBox::~COXFontListBox()
{
if(m_dcScreen!=NULL)
{
::DeleteDC(m_dcScreen);
}
CleanUpCreatedFonts();
}
BEGIN_MESSAGE_MAP(COXFontListBox, COXListBoxEx)
//{{AFX_MSG_MAP(COXFontListBox)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// COXFontListBox message handlers
void COXFontListBox::PreSubclassWindow()
{
// TODO: Add your specialized code here and/or call the base class
DWORD dwStyle=GetStyle();
// make sure LBS_HASSTRINGS style is specified
ASSERT(dwStyle & LBS_HASSTRINGS);
// make sure LBS_SORT style hasn't been set
ASSERT(!(dwStyle & LBS_SORT));
COXListBoxEx::PreSubclassWindow();
}
BOOL COXFontListBox::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Add your specialized code here and/or call the base class
// make sure LBS_SORT style hasn't been set
cs.style&=~LBS_SORT;
// make sure LBS_HASSTRINGS style is specified
cs.style|=LBS_HASSTRINGS;
return COXListBoxEx::PreCreateWindow(cs);
}
BOOL COXFontListBox::InitializeListBox()
{
ASSERT(::IsWindow(GetSafeHwnd()));
if(GetCount()>0)
{
ResetContent();
}
if(!COXListBoxEx::InitializeListBox())
{
return FALSE;
}
SetRedraw(FALSE);
PopulateWithFonts();
if(GetSaveRestoreMRUState())
{
RestoreMRUState();
}
SetRedraw(TRUE);
return TRUE;
}
void COXFontListBox::DrawText(CDC* pDC, LPCTSTR lpszText, CRect& rectText,
COLORREF clrText, CFont* pFont)
{
CString sText=lpszText;
if(!sText.IsEmpty())
{
int nFontIndex=-1;
if(m_mapCreatedFonts.Lookup(pFont,nFontIndex))
{
ASSERT(nFontIndex>=0 && nFontIndex<m_arrFonts.GetSize());
OXLBFONTINFO& lbfi=m_arrFonts[nFontIndex];
if(lbfi.m_bIsSymbol)
{
sText.Format(_T("[%s]"),lpszText);
pFont=GetFont();
}
}
}
COXListBoxEx::DrawText(pDC,sText,rectText,clrText,pFont);
}
void COXFontListBox::CalcTextSize(int nIndex, int& nWidthText, int& nHeightText)
{
if(GetStyle()&LBS_HASSTRINGS)
{
OXLISTBOXITEM* pLBI=GetItemInfo(nIndex);
ASSERT(pLBI!=NULL);
CString sText;
GetText(nIndex,sText);
CFont* pFont=pLBI->m_pFont;
int nFontIndex=-1;
if(m_mapCreatedFonts.Lookup(pFont,nFontIndex))
{
ASSERT(nFontIndex>=0 && nFontIndex<m_arrFonts.GetSize());
OXLBFONTINFO& lbfi=m_arrFonts[nFontIndex];
if(lbfi.m_bIsSymbol)
{
sText=_T("[")+sText+_T("]");
pFont=GetFont();
}
}
CClientDC dc(this);
CFont* pOldFont=NULL;
if(pFont!=NULL)
{
pOldFont=dc.SelectObject(pFont);
}
CRect rectText(0, 0, 0, 0);
int nRet = dc.DrawText(sText,rectText,DT_CALCRECT|DT_LEFT|DT_SINGLELINE);
if( nRet > 5000 || nRet < 1 )
{
nWidthText=0;
nHeightText=0;
return;
}
if(pOldFont!=NULL)
{
dc.SelectObject(pOldFont);
}
nWidthText=rectText.Width();
nHeightText=rectText.Height();
}
else
{
nWidthText=0;
nHeightText=0;
}
}
void COXFontListBox::SetDC(HDC dc)
{
if(m_dc==dc)
{
return;
}
m_dc=dc;
if(::IsWindow(GetSafeHwnd()))
{
SaveMRUState(_T("FontListBox_MRU_ABCDEFG_0123456_Copy"));
PopulateWithFonts();
RestoreMRUState(_T("FontListBox_MRU_ABCDEFG_0123456_Copy"));
}
}
void COXFontListBox::SetFontHeight(int nHeight)
{
if(m_nFontHeight==nHeight)
{
return;
}
m_nFontHeight=nHeight;
if(::IsWindow(GetSafeHwnd()))
{
for(int nIndex=0; nIndex<m_mapItems.GetCount(); nIndex++)
{
OXLISTBOXITEM* pLBI=GetItemInfo(nIndex);
ASSERT(pLBI!=NULL);
if(pLBI->m_pFont!=NULL)
{
int nOrigIndex=-1;
if(m_mapCreatedFonts.Lookup(pLBI->m_pFont,nOrigIndex))
{
ASSERT(nOrigIndex>=0 && nOrigIndex<m_arrFonts.GetSize());
m_arrFonts[nOrigIndex].m_lf.lfHeight=GetFontHeight();
m_mapCreatedFonts.RemoveKey(pLBI->m_pFont);
delete pLBI->m_pFont;
pLBI->m_pFont=NULL;
CFont* pFont=new CFont;
VERIFY(pFont->CreateFontIndirect(&m_arrFonts[nOrigIndex].m_lf));
m_mapCreatedFonts.SetAt(pFont,nOrigIndex);
SetItemFont(nIndex,pFont);
}
}
}
}
}
BOOL COXFontListBox::PopulateWithFonts()
{
CWaitCursor wait;
ResetContent();
m_arrFonts.RemoveAll();
CleanUpCreatedFonts();
HDC hDC=::GetDC(NULL);
if(hDC==NULL) // use screen as default
{
if(m_dcScreen==NULL)
{
m_dcScreen=::CreateDC(TEXT("DISPLAY"),NULL,NULL,NULL);
}
m_dc=m_dcScreen;
}
::EnumFonts(hDC,NULL,FontListBoxEnumFontProc,(LPARAM)this);
::ReleaseDC(NULL,hDC);
// now sort by facename
if (m_arrFonts.GetSize()>0)
{
::qsort(&m_arrFonts[0],m_arrFonts.GetSize(),sizeof(OXLBFONTINFO),
FontEntrySortFunc);
}
// now eliminate duplicates - choose TT in preference
int nIndex=0;
for(nIndex=1; nIndex<m_arrFonts.GetSize(); nIndex++)
{
if (!_tcsicmp(m_arrFonts[nIndex].m_lf.lfFaceName,
m_arrFonts[nIndex-1].m_lf.lfFaceName))
{
// remove duplicate
if(m_arrFonts[nIndex].m_dwType & TRUETYPE_FONTTYPE)
{
m_arrFonts.RemoveAt(--nIndex);
}
else
{
m_arrFonts.RemoveAt(nIndex--);
}
}
}
// populate list box
for(nIndex=0; nIndex<m_arrFonts.GetSize(); nIndex++)
{
CFont* pFont=new CFont;
VERIFY(pFont->CreateFontIndirect(&m_arrFonts[nIndex].m_lf));
m_mapCreatedFonts.SetAt(pFont,nIndex);
OXLISTBOXITEM lbi;
lbi.m_pFont=pFont;
lbi.m_nImageIndex=(m_arrFonts[nIndex].m_dwType==TRUETYPE_FONTTYPE ? 1 : 0);
lbi.m_sTooltipText=m_arrFonts[nIndex].m_lf.lfFaceName;
VERIFY(AddString(m_arrFonts[nIndex].m_lf.lfFaceName,
OXLBI_FONT|OXLBI_IMAGEINDEX,&lbi)!=LB_ERR);
}
return TRUE;
}
void COXFontListBox::CleanUpCreatedFonts()
{
POSITION pos=m_mapCreatedFonts.GetStartPosition();
while(pos!=NULL)
{
int nIndex=0;
CFont* pFont=NULL;
m_mapCreatedFonts.GetNextAssoc(pos,pFont,nIndex);
ASSERT(pFont!=NULL);
delete pFont;
}
m_mapCreatedFonts.RemoveAll();
}
CFont* COXFontListBox::GetSelectedFont()
{
ASSERT(::IsWindow(GetSafeHwnd()));
int nIndex=GetCurSel();
if(nIndex==LB_ERR)
{
return NULL;
}
else
{
return GetItemFont(nIndex);
}
}
int COXFontListBox::SelectFont(CFont* pFont)
{
ASSERT(::IsWindow(GetSafeHwnd()));
ASSERT(pFont!=NULL);
LOGFONT lf;
if(!pFont->GetLogFont(&lf))
{
TRACE(_T("COXFontListBox::SelectFont: faile to retrieve log info for specified CFont object\n"));
return LB_ERR;
}
return SelectFont(&lf);
}
int COXFontListBox::SelectFont(LOGFONT* pLF)
{
ASSERT(::IsWindow(GetSafeHwnd()));
ASSERT(pLF!=NULL);
return SelectFont(pLF->lfFaceName);
}
int COXFontListBox::SelectFont(LPCTSTR lpszFontName)
{
ASSERT(lpszFontName!=NULL);
CString sFontName=lpszFontName;
if(sFontName.IsEmpty())
{
return SetCurSel(-1);
}
else
{
return SelectString(-1,sFontName);
}
}
int COXFontListBox::AddFormerMRUString(LPCTSTR lpszItem, int nMask,
OXLISTBOXITEM* pLBI)
{
int nIndex=0;
for(nIndex=GetCount()-1; nIndex>GetLastItemBeforeSeparator(); nIndex--)
{
CString sText;
GetText(nIndex,sText);
if(_tcsicmp(lpszItem,sText)>=0)
{
break;
}
}
nIndex++;
return InsertString(nIndex,lpszItem,nMask,pLBI);
}