Click here to Skip to main content
15,886,823 members
Articles / Desktop Programming / MFC

Enhancements of Matthew R. Millers COptionTree

Rate me:
Please Sign up or sign in to vote.
4.76/5 (15 votes)
26 Apr 2006CPOL3 min read 119.8K   2.6K   58  
This article demonstrates an enhanced version of Matthew R. Millers Option Tree
// COptionTree
//
// License
// -------
// This code is provided "as is" with no expressed or implied warranty.
// 
// You may use this code in a commercial product with or without acknowledgement.
// However you may not sell this code or any modification of this code, this includes 
// commercial libraries and anything else for profit.
//
// I would appreciate a notification of any bugs or bug fixes to help the control grow.
//
// History:
// --------
//	See License.txt for full history information.
//
//
// Copyright (c) 1999-2002 
// ComputerSmarts.net 
// mattrmiller@computersmarts.net


#include "stdafx.h"
#include "OptionTreeItemImage.h"

// Added Headers
#include "OptionTree.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// COptionTreeItemImage

COptionTreeItemImage::COptionTreeItemImage()
{	
	// Initalize variables
	m_bFocus = FALSE;
	m_sImageSizes.cx = 0;
	m_sImageSizes.cy = 0;
	m_nSelected = -1;
	m_nNumColumns = 0;
	m_dwOptions = NULL;

	// Set item type
	SetItemType(OT_ITEM_IMAGE);
}

COptionTreeItemImage::~COptionTreeItemImage()
{
	// Reallocate
	if (m_imgImages.GetSafeHandle() != NULL)
	{
		m_imgImages.DeleteImageList();
	}
	m_strText.RemoveAll();
}


BEGIN_MESSAGE_MAP(COptionTreeItemImage, CWnd)
	//{{AFX_MSG_MAP(COptionTreeItemImage)
	ON_WM_LBUTTONUP()
	ON_WM_KILLFOCUS()
	ON_WM_SETFOCUS()
	ON_WM_PAINT()
	ON_WM_ERASEBKGND()
	//}}AFX_MSG_MAP
	ON_MESSAGE(OT_IMAGE_CLOSE, OnPopUpClose)
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// COptionTreeItemImage message handlers

void COptionTreeItemImage::DrawAttribute(CDC *pDC, const RECT &rcRect)
{
	// If we don't have focus, text is drawn.
	if (m_bFocus == TRUE)
	{

		return;
	}

	// Make sure options aren't NULL
	if (m_otOption == NULL)
	{
		return;
	}

	// Make sure there is a window
	if (!IsWindow(GetSafeHwnd()))
	{
		return;
	}

	// Set window position
	if (IsWindow(GetSafeHwnd()))
	{
		SetWindowPos(NULL, m_rcAttribute.left, m_rcAttribute.top, m_rcAttribute.Width(), m_rcAttribute.Height(), SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW);
	}

	// Draw control
	DrawControl(pDC, rcRect);
}

void COptionTreeItemImage::OnCommit()
{
	// Hide window
	if (IsWindow(GetSafeHwnd()))
	{
		// -- Show window
		ShowWindow(SW_HIDE);
	}
}

void COptionTreeItemImage::OnRefresh()
{
	// Set the window positiion
	if (IsWindow(GetSafeHwnd()))
	{
		SetWindowPos(NULL, m_rcAttribute.left, m_rcAttribute.top, m_rcAttribute.Width(), m_rcAttribute.Height(), SWP_NOZORDER | SWP_NOACTIVATE);
	}
}

void COptionTreeItemImage::OnMove()
{
	// Set window position
	if (IsWindow(GetSafeHwnd()))
	{
		SetWindowPos(NULL, m_rcAttribute.left, m_rcAttribute.top, m_rcAttribute.Width(), m_rcAttribute.Height(), SWP_NOZORDER | SWP_NOACTIVATE);
	}

	// Hide window
	if (m_bFocus == FALSE && IsWindow(GetSafeHwnd()))
	{
		// -- Show window
		ShowWindow(SW_HIDE);
	}
}

void COptionTreeItemImage::OnActivate()
{
	// Make sure window is valid
	if (IsWindow(GetSafeHwnd()))
	{
		// -- Show window
		ShowWindow(SW_SHOW);

		// -- Set window position
		SetWindowPos(NULL, m_rcAttribute.left, m_rcAttribute.top, m_rcAttribute.Width(), m_rcAttribute.Height(), SWP_NOZORDER | SWP_SHOWWINDOW);

		// -- Set focus
		SetFocus();
	}
}

void COptionTreeItemImage::CleanDestroyWindow()
{
	// Destroy window
	if (IsWindow(GetSafeHwnd()))
	{
		// -- Destroy window
		DestroyWindow();
	}
}

void COptionTreeItemImage::OnDeSelect()
{
	// Hide window
	if (IsWindow(GetSafeHwnd()))
	{
		// -- Show window
		ShowWindow(SW_HIDE);
	}
}

void COptionTreeItemImage::OnSelect()
{
}

void COptionTreeItemImage::OnLButtonUp(UINT nFlags, CPoint point) 
{	
	// Declare variables
	CPoint ptPoint;

	// Get cursor position
	GetCursorPos(&ptPoint);

	// Hide window
	if (IsWindow(GetSafeHwnd()))
	{
		// -- Show window
		ShowWindow(SW_HIDE);
	}

	// Show icon popup
	new COptionTreeImagePopUp(ptPoint, m_sImageSizes, m_nNumColumns, &m_imgImages, m_otOption, m_strText, m_nSelected, this);

	// Update items
	if (m_otOption != NULL)
	{
		m_otOption->UpdatedItems();
	}

	CWnd::OnLButtonUp(nFlags, point);
}

void COptionTreeItemImage::OnKillFocus(CWnd* pNewWnd) 
{
	// Mark focus
	m_bFocus = FALSE;

	// Commit changes
	//CommitChanges();	
	
	CWnd::OnKillFocus(pNewWnd);	
}

void COptionTreeItemImage::OnSetFocus(CWnd* pOldWnd) 
{
	// Mark focus
	m_bFocus = TRUE;
	
	CWnd::OnSetFocus(pOldWnd);
}

void COptionTreeItemImage::OnPaint() 
{
	// Check focus
	if (m_bFocus == FALSE)
	{
		return;
	}

	// Declare variables
	CPaintDC dc(this);
	CRect rcClient;

	// Get client rect
	GetClientRect(rcClient);

	// Draw control
	DrawControl(&dc, rcClient);
}

BOOL COptionTreeItemImage::OnEraseBkgnd(CDC* pDC) 
{
	// Naa, we like flicker free better
	return FALSE;
}

void COptionTreeItemImage::DrawControl(CDC *pDC, const RECT &rcRect)
{
	// Declare variables
	HGDIOBJ hOld;
	COLORREF crOld;
	int nOldBack;
	CRect rcText, rcImage, rcClient;
	CString strText;
	CBrush bBrush;
	HICON hGreyScale = NULL, hSelected=NULL;
	COLORREF crOldBack;

	// Get window rect
	GetClientRect(rcClient);

	// Select font
	hOld = pDC->SelectObject(m_otOption->GetNormalFont());
	
	// Set text color
	if (IsReadOnly() == TRUE || m_otOption->IsWindowEnabled() == FALSE)
	{
		crOld = pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));
	}
	else
	{
		crOld = pDC->SetTextColor(GetTextColor());
	}

	// Set background mode
	nOldBack = pDC->SetBkMode(TRANSPARENT);

	// Set background color
	crOldBack = pDC->SetBkColor(GetBackgroundColor());	

	// Make sure we have a selected item
	if (m_nSelected != -1 && m_nSelected < m_imgImages.GetImageCount())
	{
		// -- Get icon rectangle
		rcImage.left  = rcRect.left + 1;
		rcImage.right = rcImage.left + m_sImageSizes.cx;
		rcImage.top = rcRect.top + OT_IMAGE_IMAGESPACE;
		rcImage.bottom = rcImage.top + + m_sImageSizes.cy;

		// -- Draw image
		if (IsReadOnly() == TRUE || m_otOption->IsWindowEnabled() == FALSE)
		{
			hSelected = m_imgImages.ExtractIcon(m_nSelected);
			hGreyScale = CreateGreyScaleIcon(hSelected);
			pDC->DrawState(CPoint(rcImage.left, rcImage.top), m_sImageSizes, (HICON)hGreyScale, DST_ICON | DSS_NORMAL, (CBrush*)NULL);
		}
		else
		{
			m_imgImages.Draw(pDC, m_nSelected, CPoint(rcImage.left, rcImage.top), ILD_NORMAL);
		}


		// -- Get text rectangle
		rcText.left  = rcImage.right + ATTRIB_OFFSET;
		rcText.right = rcRect.right;
		rcText.top = rcRect.top;
		rcText.bottom = rcRect.bottom;

		// -- Get text
		if (GetOption(OT_IMAGE_SHOWTEXT) == TRUE)
		{
			strText = m_strText.GetAt(m_nSelected);
		}
	}
	else
	{
		// -- Get text rectangle
		rcText.left  = rcRect.left + 1;
		rcText.right = rcRect.right;
		rcText.top = rcRect.top;
		rcText.bottom = rcRect.bottom;

		// -- No image selected
		strText = OT_IMAGE_NOSELECTION;
	}


	// Draw text
	pDC->DrawText(strText, rcText, DT_SINGLELINE | DT_VCENTER);
	pDC->DrawText(strText, rcText, DT_SINGLELINE | DT_VCENTER | DT_CALCRECT);

	// Restore GDI ojects
	pDC->SelectObject(hOld);
	pDC->SetTextColor(crOld);
	pDC->SetBkMode(nOldBack);
	pDC->SetBkColor(crOldBack);

	// Delete grey icon
	if (hSelected != NULL)
	{
		::DestroyIcon(hSelected);
	}
	if (hGreyScale != NULL)
	{
		::DestroyIcon(hGreyScale);
	}
}

BOOL COptionTreeItemImage::CreateImageItem(DWORD dwOptions, CSize sImageSizes, int nNumberColumns)
{
	// Declare variables
	DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
	BOOL bRet = FALSE;

	// Make sure options is not NULL
	if (m_otOption == NULL)
	{
		return FALSE;
	}

	// Create window
	if (!IsWindow(GetSafeHwnd()))
	{
		// -- Create the edit view
		bRet = Create(AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW, ::LoadCursor(NULL, IDC_ARROW)), _T(""), dwStyle, m_rcAttribute, m_otOption->GetCtrlParent(), GetCtrlID());

		// -- Setup window
		if (bRet == TRUE)
		{
			// -- -- Set font
			SetFont(m_otOption->GetNormalFont(), TRUE);

			// -- -- Save options
			m_dwOptions = dwOptions;

			// -- -- Create imagelist
			if (m_imgImages.GetSafeHandle() != NULL)
			{
				m_imgImages.DeleteImageList();
			}
			if (!m_imgImages.Create(sImageSizes.cx, sImageSizes.cy, ILC_COLORDDB | ILC_MASK, 1, OT_IMAGE_MAXIMAGES))
			{
				bRet = FALSE;
			}	

			// -- -- Set item height
			SetItemHeight((long) sImageSizes.cy + (OT_IMAGE_IMAGESPACE * 2));

			// -- -- Set number of columns
			SetNumberColumns(nNumberColumns);

			// Set image height
			SetImageSize(sImageSizes);

			// -- -- Set window position
			SetWindowPos(NULL, m_rcAttribute.left, m_rcAttribute.top, m_rcAttribute.Width(), m_rcAttribute.Height(), SWP_NOZORDER | SWP_SHOWWINDOW);

			// -- -- Hide window
			ShowWindow(SW_HIDE);
		}
	}

	return bRet;
}

void COptionTreeItemImage::SetImageSize(CSize sSize)
{
	m_sImageSizes = sSize;
}

CSize COptionTreeItemImage::GetImageSize()
{
	return m_sImageSizes;
}

void COptionTreeItemImage::SetNumberColumns(int nNum)
{
	m_nNumColumns = nNum;
}


void COptionTreeItemImage::AddIcon(HICON hIcon, CString strText)
{
	// Add image
	m_imgImages.Add(hIcon);

	// Add text
	m_strText.Add(strText);
}

void COptionTreeItemImage::AddIcon(UINT uIcon, CString strText)
{
	// Add icon
	AddIcon((HICON) LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(uIcon), IMAGE_ICON, m_sImageSizes.cx, m_sImageSizes.cy, LR_DEFAULTCOLOR), strText);
}

void COptionTreeItemImage::AddIcon(CString strIcon, CString strText)
{
	// Add icon
	AddIcon((HICON) LoadImage(AfxGetInstanceHandle(), strIcon, IMAGE_ICON, m_sImageSizes.cx, m_sImageSizes.cy, LR_DEFAULTCOLOR), strText);
}

void COptionTreeItemImage::AddBitmap(CBitmap &bBitmap, COLORREF crMask, CString strText)
{
	// Add image
	m_imgImages.Add(&bBitmap, crMask);

	// Add text
	m_strText.Add(strText);
}

void COptionTreeItemImage::AddBitmap(UINT uBitmap, COLORREF crMask, CString strText)
{
	// Declare variables
	CBitmap bBitmap;

	// Load bitmap
	bBitmap.LoadBitmap(uBitmap);

	// Add bitmap
	AddBitmap(bBitmap, crMask, strText);
}

void COptionTreeItemImage::AddBitmap(CString strBitmap, COLORREF crMask, CString strText)
{
	// Declare variables
	CBitmap bBitmap;

	// Load bitmap
	bBitmap.LoadBitmap(strBitmap);

	// Add bitmap
	AddBitmap(bBitmap, crMask, strText);
}

int COptionTreeItemImage::GetSelection()
{
	return m_nSelected;
}

void COptionTreeItemImage::SetSelection(int nSelection)
{
	m_nSelected = nSelection;
}

BOOL COptionTreeItemImage::GetBitmapFromImageList(CDC *pDC, HICON hIcon, CBitmap &bmp)
{
	// Declare varaibles
	CDC dc;
	CBrush brush;

	dc.CreateCompatibleDC(pDC);
	bmp.CreateCompatibleBitmap(pDC, m_sImageSizes.cx, m_sImageSizes.cy);
	CBitmap* pOldBmp = dc.SelectObject(&bmp);
	brush.CreateSolidBrush(GetSysColor(COLOR_MENU));
	::DrawIconEx(dc.GetSafeHdc(), 0, 0, hIcon, m_sImageSizes.cx, m_sImageSizes.cy, 0, (HBRUSH)brush,DI_NORMAL);

	// Restore
	dc.SelectObject(pOldBmp);

	// Delete
	if (brush.GetSafeHandle() != NULL)
	{
		brush.DeleteObject();
	}
	if (dc.GetSafeHdc() != NULL)
	{
		dc.DeleteDC();
	}

	// The icon is not longer needed
	DestroyIcon(hIcon);

	return TRUE;
}

void COptionTreeItemImage::DitherBlt(CDC *drawdc, int nXDest, int nYDest, int nWidth, int nHeight, CBitmap &bmp, int nXSrc, int nYSrc)
{
	// Create a monochrome memory DC
	CDC ddc;
	ddc.CreateCompatibleDC(0);
	CBitmap bwbmp;
	bwbmp.CreateCompatibleBitmap(&ddc, nWidth, nHeight);
	CBitmap * pddcOldBmp = ddc.SelectObject(&bwbmp);
	CDC dc;
	dc.CreateCompatibleDC(0);
	CBitmap * pdcOldBmp = dc.SelectObject(&bmp);
	COLORREF crOldback, crOldText;
	
	// Build a mask
	ddc.PatBlt(0, 0, nWidth, nHeight, WHITENESS);
	crOldback = dc.SetBkColor(GetSysColor(COLOR_BTNFACE));
	ddc.BitBlt(0, 0, nWidth, nHeight, &dc, nXSrc,nYSrc, SRCCOPY);
	dc.SetBkColor(GetSysColor(COLOR_BTNHILIGHT));
	ddc.BitBlt(0, 0, nWidth, nHeight, &dc, nXSrc,nYSrc, SRCPAINT);

	// Copy the image from the toolbar into the memory DC
	// and draw it (grayed) back into the toolbar.
	dc.FillSolidRect(0,0, nWidth, nHeight, GetSysColor((TRUE/*IsNewShell()*/)?COLOR_3DFACE:COLOR_MENU));
	
	// SK: Looks better on the old shell
	dc.SetBkColor(RGB(0, 0, 0));
	crOldText = dc.SetTextColor(RGB(255, 255, 255));
	CBrush brShadow, brHilight;
	brHilight.CreateSolidBrush(GetSysColor(COLOR_BTNHILIGHT));
	brShadow.CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW));
	CBrush * pOldBrush = dc.SelectObject(&brHilight);
	dc.BitBlt(0,0, nWidth, nHeight, &ddc, 0, 0, 0x00E20746L);
	drawdc->BitBlt(nXDest+1,nYDest+1,nWidth, nHeight, &dc,0,0,SRCCOPY);
	dc.BitBlt(1,1, nWidth, nHeight, &ddc, 0, 0, 0x00E20746L);
	dc.SelectObject(&brShadow);
	dc.BitBlt(0,0, nWidth, nHeight, &ddc, 0, 0, 0x00E20746L);
	drawdc->BitBlt(nXDest,nYDest,nWidth, nHeight, &dc,0,0,SRCCOPY);
	
	// Restore DCs
	ddc.SelectObject(pddcOldBmp);
	dc.SelectObject(pOldBrush);
	dc.SelectObject(pdcOldBmp);
	dc.SetBkColor(crOldback);
	dc.SetTextColor(crOldText);

	// Delete
	if (bwbmp.GetSafeHandle() != NULL)
	{
		bwbmp.DeleteObject();
	}
	if (brHilight.GetSafeHandle() != NULL)
	{
		brHilight.DeleteObject();
	}
	if (brShadow.GetSafeHandle() != NULL)
	{
		brShadow.DeleteObject();
	}
	if (ddc.GetSafeHdc() != NULL)
	{
		ddc.DeleteDC();
	}
	if (dc.GetSafeHdc() != NULL)
	{
		dc.DeleteDC();
	}
}

long COptionTreeItemImage::OnPopUpClose(UINT lParam, long wParam)
{
  if((int) wParam != GetSelection())
  {
	  // Get selected
	  SetSelection((int) wParam);

	  // Hide window
	  if (IsWindow(GetSafeHwnd()))
	  {
		  // -- Show window
		  ShowWindow(SW_HIDE);
	  }

	  // Kill focus so we can draw attribute
	  m_bFocus = FALSE;

	  // Update items
	  if (m_otOption != NULL)
	  {
		  m_otOption->UpdatedItems();
	  }
    CommitChanges();
  }
  return TRUE;
}

HICON COptionTreeItemImage::CreateGreyScaleIcon(HICON hIcon)
{
	// Declare variables
    HICON hGrayIcon = NULL;
    HDC hMainDC = NULL, hMemDC1 = NULL, hMemDC2 = NULL;
    BITMAP bmp;
    HBITMAP hOldBmp1 = NULL, hOldBmp2 = NULL;
    ICONINFO csII, csGrayII;
    BOOL bRetValue = FALSE;

    bRetValue = ::GetIconInfo(hIcon, &csII);
    if (bRetValue == FALSE) return NULL;

	hMainDC = ::GetDC(::GetDesktopWindow());  
	if (hMainDC == NULL) 
		return NULL;  
	hMemDC1 = ::CreateCompatibleDC(hMainDC);  
	hMemDC2 = ::CreateCompatibleDC(hMainDC);  
	if (hMemDC1 == NULL || hMemDC2 == NULL) 
		return NULL; 
  
    if (::GetObject(csII.hbmColor, sizeof(BITMAP), &bmp))
    {
        csGrayII.hbmColor = ::CreateBitmap(csII.xHotspot*2, csII.yHotspot*2, 
                                           bmp.bmPlanes, bmp.bmBitsPixel, NULL);
        if (csGrayII.hbmColor)
        {
            hOldBmp1 = (HBITMAP)::SelectObject(hMemDC1, csII.hbmColor);
            hOldBmp2 = (HBITMAP)::SelectObject(hMemDC2, csGrayII.hbmColor);

            ::BitBlt(hMemDC2, 0, 0, csII.xHotspot*2, csII.yHotspot*2, hMemDC1, 
                     0, 0, SRCCOPY);

            DWORD    dwLoopY = 0, dwLoopX = 0;
            COLORREF crPixel = 0;
            BYTE     byNewPixel = 0;

            for (dwLoopY = 0; dwLoopY < csII.yHotspot*2; dwLoopY++)
            {
                for (dwLoopX = 0; dwLoopX < csII.xHotspot*2; dwLoopX++)
                {
                    crPixel = ::GetPixel(hMemDC2, dwLoopX, dwLoopY);

                    byNewPixel = (BYTE)((GetRValue(crPixel) * 0.299) + 
                                        (GetGValue(crPixel) * 0.587) + 
                                        (GetBValue(crPixel) * 0.114));
                    if (crPixel) ::SetPixel(hMemDC2, dwLoopX, dwLoopY, 
                                            RGB(byNewPixel, byNewPixel, byNewPixel));
                } // for
            } // for

            ::SelectObject(hMemDC1, hOldBmp1);
            ::SelectObject(hMemDC2, hOldBmp2);

            csGrayII.hbmMask = csII.hbmMask;

            csGrayII.fIcon = TRUE;
            hGrayIcon = ::CreateIconIndirect(&csGrayII);
        } // if

        ::DeleteObject(csGrayII.hbmColor);
        //::DeleteObject(csGrayII.hbmMask);
    } // if

    ::DeleteObject(csII.hbmColor);
    ::DeleteObject(csII.hbmMask);
    ::DeleteDC(hMemDC1);
    ::DeleteDC(hMemDC2);
    //::ReleaseDC(m_hWnd, hMainDC);

    return hGrayIcon;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions