Category : C++ Source Code
Archive   : HIERLIST.ZIP
Filename : LSTBOXEX.CPP

 
Output of file : LSTBOXEX.CPP contained in archive : HIERLIST.ZIP
// lstboxex.cpp : implementation file
//
#include "stdafx.h"

#include "resource.h"

#include "lstboxex.h"

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

IMPLEMENT_DYNAMIC(CListBoxEx,CListBox);

BEGIN_MESSAGE_MAP(CListBoxEx, CListBox)
//{{AFX_MSG_MAP(CListBoxEx)
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_RBUTTONDOWN()
ON_WM_CANCELMODE()
ON_WM_CREATE()
ON_WM_MOUSEMOVE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()


CListBoxExResources::CListBoxExResources(
WORD bmId, WORD bmWidth,
WORD idCursNoDrop,
WORD idCursCopySingle, WORD idCursCopyMulti,
WORD idCursMoveSingle, WORD idCursMoveMulti,
COLORREF t1, COLORREF t2 )
{
m_BitMapId = bmId;

m_ColorTransparent1 = t1;
m_ColorTransparent2 = t2;

// the bitmap width is for information only - the user of the CListBoxExResources object needs to
// know the layout of the bitmap but the bitmap height is calculated from the height of the loaded
// bitmap assuming it is a two high bitmap
m_BitmapWidth = bmWidth;
m_BitmapHeight = 0;

CWinApp* app = AfxGetApp();
m_hCursorCopyMultiple = app->LoadCursor( idCursCopyMulti );
m_hCursorCopySingle = app->LoadCursor( idCursCopySingle );
m_hCursorMoveMultiple = app->LoadCursor( idCursMoveMulti );
m_hCursorMoveSingle = app->LoadCursor( idCursMoveSingle );
m_hCursorNoDrop = app->LoadCursor( idCursNoDrop );

ASSERT( m_hCursorCopyMultiple && m_hCursorCopySingle && m_hCursorMoveSingle && \
m_hCursorMoveMultiple && m_hCursorNoDrop );

GetSysColors();
PrepareBitmaps( FALSE );
}

CListBoxExResources::~CListBoxExResources()
{
UnprepareBitmaps();
}

void CListBoxExResources::UnprepareBitmaps()
{
CBitmap* pBmp = (CBitmap*)CGdiObject::FromHandle(m_hOldBitmap);
ASSERT(pBmp);
VERIFY(m_dcFinal.SelectObject(pBmp));
VERIFY(m_dcFinal.DeleteDC());
VERIFY(m_BmpScreen.DeleteObject());
}

void CListBoxExResources::PrepareBitmaps( BOOL reinit )
{
ASSERT( m_BitMapId );

if( reinit )
UnprepareBitmaps();

CDC dcImage;
CDC dcMasks;

// create device contexts compatible with screen
VERIFY(dcImage.CreateCompatibleDC(0));
VERIFY(dcMasks.CreateCompatibleDC(0));

VERIFY(m_dcFinal.CreateCompatibleDC(0));

CBitmap bitmap;
VERIFY(bitmap.LoadBitmap(m_BitMapId));

BITMAP bm;
VERIFY(bitmap.GetObject(sizeof(BITMAP),&bm));

const int bmWidth = bm.bmWidth;
// two high bitmap assumed
const int bmHeight = bm.bmHeight/2;
m_BitmapHeight = bmHeight;

CBitmap* pOldImageBmp = dcImage.SelectObject(&bitmap);
ASSERT(pOldImageBmp);

CBitmap BmpMasks;
VERIFY(BmpMasks.CreateBitmap( bmWidth,bmHeight*2,1,1,NULL ));

CBitmap* pOldMaskBmp = (CBitmap*)dcMasks.SelectObject(&BmpMasks);
ASSERT(pOldMaskBmp);

// create the foreground and object masks
COLORREF crOldBk = dcImage.SetBkColor( m_ColorTransparent1 );
dcMasks.BitBlt( 0, 0, bmWidth, bmHeight, &dcImage, 0, 0, SRCCOPY );
dcImage.SetBkColor( m_ColorTransparent2 );
dcMasks.BitBlt( 0, 0, bmWidth, bmHeight, &dcImage, 0, bmHeight, SRCAND );
dcImage.SetBkColor( crOldBk );
dcMasks.BitBlt( 0, bmHeight, bmWidth, bmHeight, &dcMasks, 0, 0, NOTSRCCOPY );

// create DC to hold final image
VERIFY(m_BmpScreen.CreateCompatibleBitmap( &dcImage, bmWidth, bmHeight*2 ));
CBitmap* pOldBmp = (CBitmap*)m_dcFinal.SelectObject(&m_BmpScreen);
ASSERT(pOldBmp);
m_hOldBitmap = pOldBmp->m_hObject;

CBrush b1;
VERIFY(b1.CreateSolidBrush( m_ColorHighlight ));
CBrush b2;
VERIFY(b2.CreateSolidBrush( m_ColorWindow ));

m_dcFinal.FillRect( CRect(0,0,bmWidth,bmHeight), &b1 );
m_dcFinal.FillRect( CRect(0,bmHeight,bmWidth,bmHeight*2), &b2 );

// mask out the object pixels in the destination
m_dcFinal.BitBlt(0,0,bmWidth,bmHeight,&dcMasks,0,0,SRCAND);
// mask out the background pixels in the image
dcImage.BitBlt(0,0,bmWidth,bmHeight,&dcMasks,0,bmHeight,SRCAND);
// XOR the revised image into the destination
m_dcFinal.BitBlt(0,0,bmWidth,bmHeight,&dcImage,0,0,SRCPAINT);

// mask out the object pixels in the destination
m_dcFinal.BitBlt(0,bmHeight,bmWidth,bmHeight,&dcMasks,0,0,SRCAND);
// XOR the revised image into the destination
m_dcFinal.BitBlt(0,bmHeight,bmWidth,bmHeight,&dcImage,0,0,SRCPAINT);

VERIFY(dcMasks.SelectObject(pOldMaskBmp));
VERIFY(dcImage.SelectObject(pOldImageBmp));

// the result of all of this messing about is a bitmap identical with the
// one loaded from the resources but with the lower row of bitmaps having
// their background changed from transparent1 to the window
// background and the upper row having their background changed from transparent2 to the
// highlight colour. A derived CListBoxEx can BitBlt the relevant part
// of the image into an item's device context for a transparent bitmap effect
// which does not take any extra time over a normal BitBlt.
}

void CListBoxExResources::SysColorChanged()
{
// reinitialise bitmaps and syscolors
// this should be called from the parent of the CListBoxExResources object
// from the OnSysColorChange() function.
GetSysColors();
PrepareBitmaps( TRUE );
}

void CListBoxExResources::GetSysColors()
{
m_ColorWindow = ::GetSysColor(COLOR_WINDOW);
m_ColorHighlight = ::GetSysColor(COLOR_HIGHLIGHT);
m_ColorWindowText = ::GetSysColor(COLOR_WINDOWTEXT);
m_ColorHighlightText = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
}

/////////////////////////////////////////////////////////////////////////////
// CListBoxEx


CListBoxEx::CListBoxEx()
{
m_bMultiple = FALSE;
m_bTracking = FALSE;
m_bTracking1 = FALSE;
m_bTrackingEnabled = TRUE;
m_bDragSingle = TRUE;
m_hOldCursor = NULL;
m_hOldTrackCursor = NULL;
m_bCopy = TRUE;

m_lfHeight = 0;

m_pResources = 0;
}


CListBoxEx::~CListBoxEx()
{
}

void CListBoxEx::AttachResources( const CListBoxExResources* r )
{
if( r != m_pResources )
{
ASSERT(r);
m_pResources = r;

if( m_hWnd ) // if window created
Invalidate();
}
}

void CListBoxEx::MeasureItem( LPMEASUREITEMSTRUCT lpMIS )
{
ASSERT(m_pResources);

int h = lpMIS->itemHeight;
int ch = TextHeight();
int bmHeight = m_pResources->BitmapHeight();

lpMIS->itemHeight = (ch }

void CListBoxEx::EnableDragDrop( BOOL enable_dd )
{
if( !enable_dd )
if( m_bTracking )
CancelTracking();

m_bTrackingEnabled = enable_dd;
}

int CListBoxEx::ItemFromPoint( const CPoint& point )
{
// Find the index of the item pointed to from the point.

// This method isn't the fastest but it does cope with variable height items.

CRect clientrect;
GetClientRect(clientrect);

int top = GetTopIndex();
int num = GetCount();

CRect itemrect;

for( int i=top; i {
GetItemRect(i,&itemrect);
if( itemrect.PtInRect(point) )
return i;

CPoint tl = itemrect.TopLeft();
if( !clientrect.PtInRect(tl) )
break;
}

return LB_ERR;
}

/////////////////////////////////////////////////////////////////////////////
// CListBoxEx message handlers

void CListBoxEx::OnLButtonDown(UINT nFlags, CPoint point)
{
if( (GetFocus() != this) ) // || (nFlags&(MK_SHIFT|MK_CONTROL)) )
{
CListBox::OnLButtonDown(nFlags,point);
return;
}

int item = ItemFromPoint(point);

if( item != LB_ERR )
{
if(m_bMultiple)
{
int selState = GetSel(item);
if( selState > 0 )
{
m_MouseDownPoint = point;
m_bDragSingle = (GetSelCount()==1);
StartTracking(TRUE);
}
}
else
{
int sel = GetCurSel();
if( sel >= 0 )
{
if( sel == item )
{
m_MouseDownPoint = point;
m_bDragSingle = TRUE;
StartTracking(TRUE);
}
}
}
}

if( !m_bTracking )
CListBox::OnLButtonDown(nFlags, point);
}

void CListBoxEx::StartTracking( BOOL start, WORD nFlags )
{
ASSERT(m_pResources);

if( m_bTrackingEnabled )
{
if(start)
{
m_bTracking = TRUE;
SetCapture();
}
else
{
m_bTracking1 = TRUE;

// default is copy
HCURSOR hCursor = 0;
m_bCopy = (nFlags&MK_CONTROL)?FALSE:TRUE;

// attempt to get custom cursor for this list box
eLbExCursor type = (m_bCopy) ?
((m_bDragSingle) ? (LbExCopySingle) : (LbExCopyMultiple)) :
((m_bDragSingle) ? (LbExMoveSingle) : (LbExMoveMultiple));

hCursor = GetCursor(type);

if(!hCursor)
{
// if no custom cursor use default from resource object
hCursor = (!m_bCopy) ?
((m_bDragSingle) ? (m_pResources->CursorMoveSingle()) : (m_pResources->CursorMoveMulti())):
((m_bDragSingle) ? (m_pResources->CursorCopySingle()) : (m_pResources->CursorCopyMulti()));
}

ASSERT(hCursor);
m_hOldCursor = ::SetCursor( hCursor );
}
}
}

void CListBoxEx::CancelTracking()
{
if(m_bTracking || m_bTracking1)
{
::SetCursor(m_hOldCursor);
ReleaseCapture();
m_hOldTrackCursor = NULL;
m_bTracking = FALSE;
m_bTracking1 = FALSE;
}
}

void CListBoxEx::DroppedItemsAt( const CPoint& point )
{
// Convert drop point to screen co-ords.
CPoint screen(point);
ClientToScreen(&screen);

// Determine client window receiving drop.
CWnd* dropWnd = WindowFromPoint(screen);
if( !dropWnd )
return;

// If valid window convert screen co-ords to dropWnd client co-ords
CPoint client(screen);
dropWnd->ScreenToClient(&client);

// Inform derived class that drop has occurred.
// The derived class has to determine whether the drop is valid,
// what to send to the client, and how to send it.
DroppedItemsOnWindowAt( dropWnd, client );
}

void CListBoxEx::OnLButtonUp(UINT nFlags, CPoint point)
{
if(m_bTracking1 || m_bTracking)
{
BOOL drop = m_bTracking1;
CancelTracking();
if(drop)
DroppedItemsAt(point);
}
else
CListBox::OnLButtonUp(nFlags, point);
}

void CListBoxEx::OnRButtonDown(UINT nFlags, CPoint point)
{
int index = ItemFromPoint(point);

if( !m_bMultiple ) // no effect in single selection
return;

int selState = GetSel(index);

if( selState != LB_ERR )
SetSel( index, !selState );
}

void CListBoxEx::OnCancelMode()
{
CancelTracking();
}

BOOL CListBoxEx::ChangeFont( CFont* pFont )
{
ASSERT(m_pResources);

if( !pFont || !m_pResources )
return FALSE;

if( !m_hWnd )
return FALSE;

SetRedraw(FALSE);

SetFont(pFont,TRUE);
CalculateTextHeight(pFont);

int nItems = GetCount();
int bmHeight = m_pResources->BitmapHeight();
int h = (bmHeight>m_lfHeight)?bmHeight:m_lfHeight;
for(int i=0; i SetItemHeight(i,h);

SetRedraw(TRUE);
Invalidate();

return TRUE;
}

void CListBoxEx::CalculateTextHeight( CFont* pFont )
{
// why isn't there a CFont::GetHeight function?
CClientDC dc(this);
CFont* pOldFont = dc.SelectObject(pFont);
TEXTMETRIC tm;
dc.GetTextMetrics(&tm);
m_lfHeight = tm.tmHeight;
dc.SelectObject(pOldFont);
}

int CListBoxEx::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CListBox::OnCreate(lpCreateStruct) == -1)
return -1;

// GetFont returns non NULL when the control is in a dialog box
CFont * pFont = GetFont();

if(!pFont)
{
LOGFONT lf;
::GetObject(GetStockObject(SYSTEM_FONT), sizeof(LOGFONT), &lf);
CFont f;
f.CreateFontIndirect(&lf);

CalculateTextHeight(&f);
}
else
CalculateTextHeight(pFont);

Initialise();

return 0;
}

void CListBoxEx::Initialise()
{
m_bMultiple = (GetStyle() & (LBS_MULTIPLESEL|LBS_EXTENDEDSEL)) != 0;
}

void CListBoxEx::OnMouseMove(UINT nFlags, CPoint point)
{
if( !m_bTrackingEnabled )
{
CListBox::OnMouseMove(nFlags, point);
return;
}

ASSERT(m_pResources);

if( m_bTracking1 )
{
CPoint screen(point);
ClientToScreen(&screen);
CWnd* dropWnd = WindowFromPoint(screen);
if( !dropWnd )
return;

// If valid window convert screen co-ords to dropWnd client co-ords
CPoint client(screen);
dropWnd->ScreenToClient(&client);
if( !CanDrop( dropWnd, client, m_bCopy ) )
{
// change to no-drop cursor
if( !m_hOldTrackCursor )
{
HCURSOR hCursor = GetCursor(LbExNoDrop);
if(!hCursor)
hCursor = m_pResources->CursorNoDrop();
ASSERT(hCursor);
m_hOldTrackCursor = ::SetCursor(hCursor);
}
}
else
{
if( m_hOldTrackCursor )
{
::SetCursor(m_hOldTrackCursor);
m_hOldTrackCursor = NULL;
}
}
}
else
{
// don't start tracking until mouse has moved outside limits - like file manager
if( m_bTracking )
{
CSize movedBy = point - m_MouseDownPoint;
int cx = movedBy.cx;
int cy = movedBy.cy;

if( cx > 16 || cy > 10 || cx < -16 || cy < -10 )
StartTracking(FALSE,nFlags);
}
}

if( !m_bTracking )
CListBox::OnMouseMove(nFlags, point);
}

void CListBoxEx::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
ASSERT(m_pResources); //need to attach resources before creation/adding items

CDC* pDC = CDC::FromHandle(lpDIS->hDC);

// draw focus rectangle when no items in listbox
if(lpDIS->itemID == (UINT)-1)
{
if(lpDIS->itemAction&ODA_FOCUS)
{
// rcItem.bottom seems to be 0 for variable height list boxes
lpDIS->rcItem.bottom = m_lfHeight;
pDC->DrawFocusRect( &lpDIS->rcItem );
}
return;
}
else
{
int selChange = lpDIS->itemAction&ODA_SELECT;
int focusChange = lpDIS->itemAction&ODA_FOCUS;
int drawEntire = lpDIS->itemAction&ODA_DRAWENTIRE;

if(selChange || drawEntire)
{
BOOL sel = lpDIS->itemState & ODS_SELECTED;

COLORREF hlite = ((sel)?(m_pResources->ColorHighlight()):(m_pResources->ColorWindow()));
COLORREF textcol = ((sel)?(m_pResources->ColorHighlightText()):(m_pResources->ColorWindowText()));

pDC->SetBkColor(hlite);
pDC->SetTextColor(textcol);
// fill the retangle with the background colour the fast way.
pDC->ExtTextOut( 0, 0, ETO_OPAQUE, &lpDIS->rcItem, NULL, 0, NULL );

CListBoxExDrawStruct ds( pDC,
&lpDIS->rcItem, sel,
(DWORD)lpDIS->itemData, lpDIS->itemID,
m_pResources );
DrawItemEx( ds );
}

if( focusChange || (drawEntire && (lpDIS->itemState&ODS_FOCUS)) )
pDC->DrawFocusRect(&lpDIS->rcItem);
}
}




  3 Responses to “Category : C++ Source Code
Archive   : HIERLIST.ZIP
Filename : LSTBOXEX.CPP

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/