개발은 하는건가..

[MFC] Custom slide control 본문

C, C++, MFC

[MFC] Custom slide control

수동애비 2022. 11. 29. 13:17
반응형

CSkinSliderCtrl 을 상속받아 원하는 클래스를 만든 후 아래와 같이 CustomDrawSliderBg, CustomDrawThumb, OnSliderPosChange 를 override 하여 원하는 형태로 DC 에 그리고  필요한 이벤트를 연결하면된다.
이벤트를 연결하면된다

#pragma once
#include "SkinSliderCtrl.h"

class CTestSliderCtrl :public CSkinSliderCtrl
{
public:
	CGCSSliderCtrl();
	virtual ~CGCSSliderCtrl();

	struct CSCallback {
		void	(*OnSliderPosChange)(CGCSSliderCtrl *pSlider, int pos, void *pOwner);
		void	*pOwner;
		CSCallback::CSCallback() { ZeroMemory(this, sizeof(CSCallback)); };
	};

	void			InitControl(CSCallback *pCb = NULL, int startPos = 127, int min = 0, int max = 255);

	inline int		GetPos() { return _GetPos(); };
	inline void		SetPos(int pos) { _SetPos(pos); };

private:
	BOOL			m_bInit = FALSE;
	CFont			m_fntText;
	CSCallback		m_csCallback;

	virtual BOOL	CustomDrawSliderBg(RECT *pCtrlRect, CDC *pDC);
	virtual BOOL	CustomDrawThumb(RECT *pThumbRect, CDC *pDC);
	virtual void	OnSliderPosChange(int value);
};

 

 

CSkinSliderCtrl.h

#pragma once

#define WM_FREEZE				WM_USER + 0xF003
#define MESSAGE_SLIDER_EVENT	WM_USER + 100

#define SLIDER_BEFORE_MOVE		1
#define SLIDER_AFTER_MOVE		2
#define SLIDER_SETPOS_MOVE		3


typedef struct {
	void		*pThis;
	LONGLONG	llValue;
} CSliderParam;


class CSkinSliderCtrl : public CSliderCtrl
{
	DECLARE_DYNAMIC(CSkinSliderCtrl)
public: 
	
	void		_GetRange(int& nLower, int& nUpper);	
	void		_SetRange(short nLower, short nUpper);	
	void		_SetRange32(int nLower, int nUpper);
	
	COLORREF	_SetBkColor(COLORREF clrNew);	
	COLORREF	_SetThumbColor(COLORREF clrNew);	
	COLORREF	_SetChColor(COLORREF clrNew);
	
	int			_GetPos(void);	
	int			_OffsetPos(int nPos);	
	int			_SetPos(int nPos);	
	int			_SetStep(int nStep);	
	int			_StepIt(void);
	
	BOOL		Freeze(void);
	void		SetFreeze(BOOL freeze);
	inline BOOL IsFreeze() { return m_bFreezed; };
	
	
	HRESULT		_EnableBorders(BOOL bEnable=TRUE);
	BOOL		_IsEnabled(void);

	void		setThumbSkin(UINT imgOut, UINT imgOver = -1);
	void		setProgressSkin(UINT img);
	void		setBackground(UINT img);
	BOOL		isDrag();

	inline void SetHighLightRange(int nStart, int nEnd) { m_HiLightStart = nStart; m_HiLightEnd = nEnd; };

public:
	CSkinSliderCtrl();
	virtual ~CSkinSliderCtrl();

	virtual BOOL	CustomDrawSliderBg(RECT *pCtrlRect, CDC *pDC);
	virtual BOOL	CustomDrawThumb(RECT *pThumbRect, CDC *pDC);
	virtual void	OnSliderPosChange(int value);

protected:
	DECLARE_MESSAGE_MAP()
	
	void		Draw(LPNMCUSTOMDRAW pNMCD);
	void		RecursiveRect(CDC *pDC, CRect rc, COLORREF nClr, BOOL First=FALSE);
	void		RecursiveChannel(CDC *pDC, CRect rc, COLORREF nClr, BOOL First=FALSE, BOOL Vertical=FALSE,BYTE StepSize=30);

protected:		
	COLORREF	m_ProBkColor;	
	COLORREF	m_ProgressBarColor;	
	
	PBRANGE		m_ProRange;		
	int			m_ProgressPos;	
	int			m_ProgressStep;

	int			m_HiLightStart = -1;
	int			m_HiLightEnd = -1;
	
	DWORD		m_Direction;
	
	COLORREF	m_ThClOver;	
	COLORREF	m_ThClOut;	
	COLORREF	m_ThClPre;	
	COLORREF	m_ThClDef;
	
	BOOL		m_bBorders;	
	BOOL		m_bFreezed;
	
	COLORREF	tmp1,tmp2;
	BOOL		m_bBlink;

	BOOL		isKeyDown;
	BOOL		isLbuttonDown;

	HBITMAP		m_hbmMask;
	CBitmap		*m_pbtmThumbDef;
	CBitmap		*m_pbtmThumbOut;
	CBitmap		*m_pbtmThumbOver;
	CBitmap		*m_pbtmProgress;
	CBitmap		*m_pbtmBackgrand;
	
protected:

	HRESULT		DrawSliderThumb(LPNMCUSTOMDRAW pNMCD);
	HRESULT		DrawSliderBorder(LPNMCUSTOMDRAW pNMCD);
	HRESULT		DrawSliderChannel(LPNMCUSTOMDRAW pNMCD);

	void		createMask(HDC hDC, CBitmap *bmp);
	void		drawThumb(HDC hDC, int x, int y);
	void		drawProgress(HDC hDC, CRect rc);
	void		drawBackground(HDC hDC, CRect rc);
	CRect		getThumbRect();
	void		setPointToPos(CPoint point);

public:
	afx_msg void OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult);
	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
	afx_msg void OnTimer(UINT nIDEvent);
	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
	afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
	afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
	afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);
	afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
};


CSkinSliderCtrl.cpp

#include "../pch.h"
#include "SkinSliderCtrl.h"


IMPLEMENT_DYNAMIC(CSkinSliderCtrl, CSliderCtrl)

CSkinSliderCtrl::CSkinSliderCtrl()	
{
	m_ProBkColor = RGB(0, 54, 68);
	m_ThClOver = RGB(25, 25, 40);
	m_ThClOut = RGB(25, 25, 40);
	m_ThClPre = RGB(45, 45, 60);
	m_ProgressBarColor = RGB(0, 225, 225);
	m_ThClDef = m_ThClOut;
	m_ProgressStep = 10;
	
	m_bBorders = TRUE;

	m_bFreezed = FALSE;
	m_bBlink = FALSE;

	m_hbmMask = NULL;
	
	isKeyDown = FALSE;
	isLbuttonDown = FALSE;

	m_pbtmThumbDef = NULL;
	m_pbtmThumbOut = NULL;
	m_pbtmThumbOver = NULL;
	m_pbtmProgress = NULL;
	m_pbtmBackgrand = NULL;
}

CSkinSliderCtrl::~CSkinSliderCtrl()
{
	if (m_pbtmThumbOut != NULL) {
		delete m_pbtmThumbOut;
		m_pbtmThumbOut = NULL;
	}

	if (m_pbtmThumbOver != NULL) {
		delete m_pbtmThumbOver;
		m_pbtmThumbOver = NULL;
	}

	if (m_pbtmProgress != NULL) {
		delete m_pbtmProgress;
		m_pbtmProgress = NULL;
	}

	if (m_pbtmBackgrand != NULL) {
		delete m_pbtmBackgrand;
		m_pbtmBackgrand = NULL;
	}
}


BEGIN_MESSAGE_MAP(CSkinSliderCtrl, CSliderCtrl)
	ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnNMCustomdraw)
	ON_WM_MOUSEMOVE()
//	ON_WM_TIMER()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_KEYDOWN()
	ON_WM_KEYUP()
	ON_WM_MOUSEWHEEL()
END_MESSAGE_MAP()



// CSkinSliderCtrl message handlers

// Custom control drawing operations
void CSkinSliderCtrl::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);

	switch(pNMCD->dwDrawStage)
	{
	case CDDS_POSTERASE:	// After the erasing cycle is complete. 
		*pResult = CDRF_SKIPDEFAULT;
		break;
	case CDDS_POSTPAINT:	// After the painting cycle is complete. 
		*pResult = CDRF_DODEFAULT;
		break;
	case CDDS_PREERASE:		// Before the erasing cycle begins.
		*pResult = CDRF_SKIPDEFAULT;
		break;
	case CDDS_PREPAINT:		// Before the painting cycle begins. 
		*pResult = CDRF_NOTIFYITEMDRAW;
		break;
	case CDDS_ITEMPREPAINT:	// Before an item is drawn.
		switch(pNMCD->dwItemSpec)
		{
		// Identifies the channel that the slider control's thumb marker slides along. 
		case TBCD_CHANNEL:	
			if (m_bBorders) {
				DrawSliderBorder(pNMCD);
			}
			DrawSliderChannel(pNMCD);
			*pResult = CDRF_SKIPDEFAULT;
			break;
		// Identifies the increment tick marks that appear along the edge of the slider control. 
		case TBCD_TICS:	
			*pResult = CDRF_DODEFAULT;
			break;
		// Identifies the slider control's thumb marker. This is the portion of 
		// the control that the user moves.
		case TBCD_THUMB:
			if (DrawSliderThumb(pNMCD) == S_OK) {
				*pResult = CDRF_SKIPDEFAULT;
			}
			else
				*pResult = CDRF_DODEFAULT;
			break;
		default:
			*pResult = CDRF_SKIPDEFAULT;
			break;
		}
		break;

	default:
		*pResult = CDRF_DODEFAULT;
		break;
	}
}


void CSkinSliderCtrl::_GetRange(int& nLower, int& nUpper)
{
	nLower = m_ProRange.iLow;
	nUpper = m_ProRange.iHigh;
	return;
}

void CSkinSliderCtrl::_SetRange(short nLower, short nUpper)
{
	m_ProRange.iLow = nLower;
	m_ProRange.iHigh = nUpper;
	return;
}

void CSkinSliderCtrl::_SetRange32(int nLower, int nUpper)
{
	m_ProRange.iLow = nLower;
	m_ProRange.iHigh = nUpper;
	CSliderCtrl::SetRange(nLower, nUpper);
	return;
}

COLORREF CSkinSliderCtrl::_SetBkColor(COLORREF clrNew)
{
    COLORREF m_tmp = m_ProBkColor;
	m_ProBkColor = clrNew;
	int min,max;
	GetRange(min,max);
	CSliderCtrl::SetRange(min,max,TRUE);
	return m_tmp;
}

COLORREF CSkinSliderCtrl::_SetThumbColor(COLORREF clrNew)
{
    COLORREF m_tmp = m_ThClDef;
	m_ThClDef = clrNew;
	int min,max;
	GetRange(min,max);
	CSliderCtrl::SetRange(min,max,TRUE);
	return m_tmp;
}


COLORREF CSkinSliderCtrl::_SetChColor(COLORREF clrNew)
{
    COLORREF m_tmp = m_ProgressBarColor;
	m_ProgressBarColor = clrNew;
	int min,max;
	GetRange(min,max);
	CSliderCtrl::SetRange(min,max,TRUE);
	return m_tmp;
}


int CSkinSliderCtrl::_GetPos(void)
{
	return (m_ProgressPos);
}

int CSkinSliderCtrl::_OffsetPos(int nPos)
{
	int curr = m_ProgressPos;
	m_ProgressPos+= nPos;
	int min,max;
	GetRange(min,max);
	CSliderCtrl::SetRange(min,max,TRUE);
	return(curr);
}

int CSkinSliderCtrl::_SetPos(int nPos)
{
    int curr = m_ProgressPos;
	m_ProgressPos = nPos;
	int min,max;
	GetRange(min,max);
	if (isKeyDown == FALSE) {
		CSliderCtrl::SetPos(nPos);
		CSliderCtrl::SetRange(min, max, TRUE);
	}

	CSliderParam sp;
	sp.pThis = this;
	sp.llValue = nPos;

	GetParent()->SendMessage(MESSAGE_SLIDER_EVENT, SLIDER_SETPOS_MOVE, (LPARAM)&sp);

	return(curr);
}

int CSkinSliderCtrl::_SetStep(int nStep)
{
	int curr = m_ProgressStep;
	m_ProgressStep = nStep;
	return curr;
}


int CSkinSliderCtrl::_StepIt(void)
{	
	int curr = m_ProgressPos;
	int min,max;
	GetRange(min,max);
	m_ProgressPos + m_ProgressStep >= max ? m_ProgressPos += m_ProgressStep-max : m_ProgressPos += m_ProgressStep;
	CSliderCtrl::SetRange(min,max,TRUE);
	return(curr);
}


HRESULT CSkinSliderCtrl::DrawSliderBorder(LPNMCUSTOMDRAW pNMCD)
{
	RECT border;
	GetClientRect(&border);
	CDC *pDC = CDC::FromHandle(pNMCD->hdc);

	if (pDC != NULL)
	{
		pDC->FillSolidRect(&border, m_ProBkColor);
		CustomDrawSliderBg(&border, pDC);			
			
		ReleaseDC(pDC);
	}

	return S_OK;
}

BOOL CSkinSliderCtrl::CustomDrawSliderBg(RECT *pCtrlRect, CDC *pDC)
{
	// override
	return FALSE;
}

BOOL CSkinSliderCtrl::CustomDrawThumb(RECT *pThumbRect, CDC *pDC)
{
	// override
	return FALSE;
}

void CSkinSliderCtrl::OnSliderPosChange(int value)
{
	// override
}

HRESULT CSkinSliderCtrl::DrawSliderChannel(LPNMCUSTOMDRAW pNMCD)
{
	CRect crect, rcHiLight;
	double rr;
	CDC *pDC = CDC::FromHandle(pNMCD->hdc);
	crect.CopyRect(&pNMCD->rc);
	BOOL Vert=FALSE;
	if(crect.Height()>crect.Width()) Vert=TRUE;
	switch(Vert)
	{
	case TRUE:
		crect.InflateRect(3, 0, 3, 0);
		DrawEdge(pNMCD->hdc, &crect, BDR_SUNKENINNER, BF_RECT | BF_SOFT | BF_MONO);
		crect.InflateRect(1, 0, 1, 0);
		if (m_ProRange.iHigh != 0) {
			rr = (crect.Height() * m_ProgressPos) / m_ProRange.iHigh;
			crect.bottom = (LONG)rr + crect.top;
		} 
		else {
			crect.bottom = crect.top;
		}
		//crect.top = 9;
		RecursiveChannel(pDC, crect, m_ProgressBarColor, TRUE, TRUE);
		break;

	case FALSE:
		crect.InflateRect(0, 3, 0, 3);
		rcHiLight = crect;

		if (m_pbtmBackgrand == NULL) 
		{			
			pDC->FillSolidRect(crect, RGB(0, 40, 40));
			pDC->FillSolidRect(crect.left+1, crect.top+1, crect.Width()-1, crect.Height()-1, RGB(225, 225, 225));
			pDC->FillSolidRect(crect.left+1, crect.top+1, crect.Width()-2, crect.Height()-2, m_ProgressBarColor);
			//DrawEdge(pNMCD->hdc, &crect, BDR_SUNKENINNER, BF_RIGHT | BF_BOTTOM | BF_SOFT | BF_MONO);
		}
		else {
			drawBackground(pNMCD->hdc, crect);
		}
		
        if (m_ProRange.iHigh != 0) {
			rr = (crect.Width() * m_ProgressPos) / m_ProRange.iHigh;
			crect.right = (LONG)rr + crect.left;
		}
		else {
			crect.right = crect.left;
		}

#if 0
		if (m_pbtmProgress == NULL) {
			RecursiveChannel(pDC, crect, m_ProgressBarColor, TRUE);
		}
		else {
			drawProgress(pNMCD->hdc, crect);
		}
#endif


		if (m_HiLightStart != -1 && m_HiLightEnd != -1 && m_ProRange.iHigh != 0) {
			int ww = rcHiLight.Width();
			rcHiLight.left += (ww * m_HiLightStart) / m_ProRange.iHigh;
			rcHiLight.right = (ww * m_HiLightEnd) / m_ProRange.iHigh;
			
			RecursiveChannel(pDC, rcHiLight, RGB(174, 76, 98), TRUE);
		}
		break;
	}

	ReleaseDC(pDC);
	return S_OK;
}


__inline void CSkinSliderCtrl::RecursiveChannel(CDC *pDC,
											   CRect rc, COLORREF nClr,
											   BOOL First/*=FALSE*/,
											   BOOL Vertical/*=FALSE*/,
											   BYTE StepSize/*=20*/)
{
	if (pDC == NULL) {
		return;
	}

#if 1
	UINT borderColor = nClr;
	BYTE r, g, b;
	r = (BYTE)(GetRValue(nClr) * 0.5);
	g = (BYTE)(GetGValue(nClr) * 0.5);
	b = (BYTE)(GetBValue(nClr) * 0.5);

	pDC->FillSolidRect(rc, RGB(r, b, g));
	rc.DeflateRect(1, 1); 
	pDC->FillSolidRect(rc, nClr);
#else
	CBrush Brush;
	Brush.CreateSolidBrush(nClr);
	HGDIOBJ old = pDC->SelectObject(Brush);
	CPen Pen;
	Pen.CreatePen(PS_SOLID, 1, nClr);
	CPen* pOldPen = pDC->SelectObject(&Pen);
	//pDC->RoundRect(rc,CPoint(rc.Width() / 2, rc.Height() / 2));
	pDC->RoundRect(rc, CPoint(1, 1));
	First ? rc.DeflateRect(1, 1) : Vertical ? rc.DeflateRect(1, 0) : rc.DeflateRect(0, 1);
	BYTE r, g, b;
	r = GetRValue(nClr);
	g = GetGValue(nClr);
	b = GetBValue(nClr);
	StepSize + r >= 255 ? r = 255 : r = StepSize + r;	// r+=Stepsize gives warning C4244
	StepSize + g >= 255 ? g = 255 : g = StepSize + g;
	StepSize + b >= 255 ? b = 255 : b = StepSize + b;
	if (!rc.IsRectEmpty()) RecursiveRect(pDC, rc, RGB(r, g, b));
	pDC->SelectObject(old);
	pDC->SelectObject(pOldPen);
	::DeleteObject(Brush);
	::DeleteObject(Pen);
#endif	
}


HRESULT CSkinSliderCtrl::DrawSliderThumb(LPNMCUSTOMDRAW pNMCD)
{
	if (pNMCD->uItemState & CDIS_SELECTED) {
		this->m_ThClDef = this->m_ThClPre;
	}
	
	Draw(pNMCD);
	return S_OK;
}


__inline void CSkinSliderCtrl::Draw(LPNMCUSTOMDRAW pNMCD)
{
	CRect rect = getThumbRect();
	
	if (m_pbtmThumbDef != NULL) {
		drawThumb(pNMCD->hdc, rect.left, rect.top);
	}
	else {
		CDC *pDC = CDC::FromHandle(pNMCD->hdc);

		if (pDC != NULL)
		{
			if (CustomDrawThumb(&rect, pDC) == FALSE) {
				if (this->IsWindowEnabled() == FALSE)
					RecursiveChannel(pDC, &rect, RGB(10, 10, 10), TRUE);
				else
					RecursiveChannel(pDC, &rect, RGB(255, 255, 255), TRUE);
			}
			
			ReleaseDC(pDC);
		}
	}
	return;
}


__inline void CSkinSliderCtrl::RecursiveRect(CDC *pDC, CRect rc, COLORREF nClr, BOOL First/*=FALSE*/)
{
	CBrush Brush;
	Brush.CreateSolidBrush(nClr);
	HGDIOBJ old = pDC->SelectObject(Brush);
	CPen Pen;
	Pen.CreatePen(PS_SOLID,1,nClr);
	CPen* pOldPen = pDC->SelectObject(&Pen);	
	//pDC->RoundRect(rc,CPoint(rc.Width() / 2, rc.Height() / 2));
	pDC->RoundRect(rc, CPoint(1, 1));
	First?rc.DeflateRect(1,1):this->GetStyle()&TBS_VERT?rc.DeflateRect(1,0):rc.DeflateRect(0,1);
	BYTE r,g,b;
	r = GetRValue(nClr);
	g = GetGValue(nClr);
	b = GetBValue(nClr);
	if(r<=245) r+=10;
	if(g<=245) g+=10;
	if(b<=245) b+=10;

	//if(!rc.IsRectEmpty()) RecursiveRect(pDC,rc,RGB(r,g,b));

	pDC->SelectObject(old);
	pDC->SelectObject(pOldPen);
	::DeleteObject(Brush);
	::DeleteObject(Pen);
}


void CSkinSliderCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
	CRect tRect = getThumbRect();
	
	if(tRect.PtInRect(point))
	{
		if (m_pbtmThumbOver != NULL) {
			m_pbtmThumbDef = m_pbtmThumbOver;
		}
		else {
			m_ThClDef = m_ThClOver;
		}
	}
	else {
		if (m_pbtmThumbOut != NULL) {
			m_pbtmThumbDef = m_pbtmThumbOut;
		}
		else {
			m_ThClDef = m_ThClOut;
		}
	}

	if (isLbuttonDown) {
		setPointToPos(point);
		Invalidate(FALSE);
	}
	else {
		int min, max;
		GetRange(min, max);
		CSliderCtrl::SetRange(min, max, TRUE);
	}
}

void CSkinSliderCtrl::createMask(HDC hDC, CBitmap *pBmp)
{
	// 기존의 마스크를 모두 없앤다.
	if (m_hbmMask) {
		::DeleteObject(m_hbmMask);
	}

	BITMAP bm;
	pBmp->GetObject(sizeof(bm), &bm);

	// 작업 할 메모리 DC를 만듭니다.
	HDC hdcMask = ::CreateCompatibleDC(hDC);
	HDC hdcImage = ::CreateCompatibleDC(hDC);
	// 마스크의 단색 비트 맵을 만듭니다.
	m_hbmMask = ::CreateBitmap(bm.bmWidth, bm.bmHeight, 1, 1, NULL);
	// DC에 모노 비트 맵을 선택하십시오.
	HBITMAP hbmOldMask = (HBITMAP)::SelectObject(hdcMask, m_hbmMask);
	// DC에 이미지 비트 맵을 선택하십시오.
	HBITMAP hbmOldImage = (HBITMAP)::SelectObject(hdcImage, pBmp->m_hObject);
	// 투명도 색상을 왼쪽 위 픽셀로 설정합니다.
	::SetBkColor(hdcImage, ::GetPixel(hdcImage, 0, 0));
	// 마스크를 만드십시오.
	::BitBlt(hdcMask, 0, 0, bm.bmWidth, bm.bmHeight, hdcImage, 0, 0, SRCCOPY);
	// Tidy up.
	::SelectObject(hdcMask, hbmOldMask);
	::SelectObject(hdcImage, hbmOldImage);
	::DeleteDC(hdcMask);
	::DeleteDC(hdcImage);
}

void CSkinSliderCtrl::drawThumb(HDC hDC, int x, int y)
{
	ASSERT(hDC);
	if (!m_hbmMask) createMask(hDC, m_pbtmThumbDef);
	ASSERT(m_hbmMask);

	BITMAP bm;
	m_pbtmThumbDef->GetObject(sizeof(bm), &bm);
	int dx = bm.bmWidth;
	int dy = bm.bmHeight;

	// 그릴 메모리 DC를 만듭니다.
	HDC hdcOffScr = ::CreateCompatibleDC(hDC);
	// 대상 DC와 실제로 색상이 호환되는 오프 스크린 DC 용 비트 맵을 만듭니다.
	HBITMAP hbmOffScr = ::CreateBitmap(dx, dy,
		(BYTE)GetDeviceCaps(hDC, PLANES),
		(BYTE)GetDeviceCaps(hDC, BITSPIXEL),
		NULL);
	// 오프 스크린 DC로 버퍼 비트 맵을 선택하십시오.
	HBITMAP hbmOldOffScr = (HBITMAP)::SelectObject(hdcOffScr, hbmOffScr);

	// 목적지 직사각형의 이미지를 오프 스크린 버퍼 DC에 복사한다. 그래서 우리는 그것을 플레이 할 수있다.
	::BitBlt(hdcOffScr, 0, 0, dx, dy, hDC, x, y, SRCCOPY);

	// 원본 이미지에 대한 메모리 DC를 만듭니다.
	HDC hdcImage = ::CreateCompatibleDC(hDC);
	HBITMAP hbmOldImage = (HBITMAP)::SelectObject(hdcImage, m_pbtmThumbDef->m_hObject);

	// 마스크에 대한 메모리 DC를 만듭니다.
	HDC hdcMask = ::CreateCompatibleDC(hDC);
	HBITMAP hbmOldMask = (HBITMAP)::SelectObject(hdcMask, m_hbmMask);

	DWORD DSx = SRCINVERT, DSa = SRCAND;

	// 이미지를 대상과 XOR합니다.
	::SetBkColor(hdcOffScr, RGB(255, 255, 255));
	::BitBlt(hdcOffScr, 0, 0, dx, dy, hdcImage, 0, 0, DSx);
	// 대상과 마스크를 AND합니다.
	::BitBlt(hdcOffScr, 0, 0, dx, dy, hdcMask, 0, 0, DSa);
	// 이미지와 대상을 다시 XOR합니다.
	::BitBlt(hdcOffScr, 0, 0, dx, dy, hdcImage, 0, 0, DSx);

	// 결과 이미지를 화면 DC로 다시 복사합니다.
	::BitBlt(hDC, x, y, dx, dy, hdcOffScr, 0, 0, SRCCOPY);
	// Tidy up.
	::SelectObject(hdcOffScr, hbmOldOffScr);
	::SelectObject(hdcImage, hbmOldImage);
	::SelectObject(hdcMask, hbmOldMask);
	::DeleteObject(hbmOffScr);
	::DeleteDC(hdcOffScr);
	::DeleteDC(hdcImage);
	::DeleteDC(hdcMask);
}

void CSkinSliderCtrl::drawProgress(HDC hDC, CRect rc)
{
	ASSERT(hDC);
	// Create a memory DC.
	HDC hdcMem = ::CreateCompatibleDC(hDC);
	BITMAP bm;
	m_pbtmProgress->GetObject(sizeof(bm), &bm);
	// Select the bitmap into the mem DC.
	HBITMAP hbmold = (HBITMAP)::SelectObject(hdcMem, (HBITMAP)(m_pbtmProgress->m_hObject));
	// Blt the bits.
	::StretchBlt(hDC, rc.top, rc.left, rc.right - rc.left, rc.bottom - rc.top, hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
	::SelectObject(hdcMem, hbmold);
	::DeleteDC(hdcMem);
}

void CSkinSliderCtrl::drawBackground(HDC hDC, CRect rc)
{
	
	ASSERT(hDC);
	// Create a memory DC.
	HDC hdcMem = ::CreateCompatibleDC(hDC);
	BITMAP bm;
	m_pbtmBackgrand->GetObject(sizeof(bm), &bm);
	// Select the bitmap into the mem DC.
	HBITMAP hbmold = (HBITMAP)::SelectObject(hdcMem, (HBITMAP)(m_pbtmBackgrand->m_hObject));
	// Blt the bits.
	::StretchBlt(hDC, rc.top, rc.left, rc.right - rc.left, rc.bottom - rc.top, hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
	::SelectObject(hdcMem, hbmold);
	::DeleteDC(hdcMem);
}

CRect CSkinSliderCtrl::getThumbRect()
{
	CRect thumbRect;
	CRect rectchn;
	int size = 0;

	GetChannelRect(&rectchn);
	GetThumbRect(&thumbRect);

	if (GetRangeMax() > 0 && GetPos() > 0) {
		if (rectchn.Height() < rectchn.Width()) {
			size = rectchn.Width() * GetPos() / GetRangeMax();
		}
		else {
			size = rectchn.Height() * GetPos() / GetRangeMax();
		}
	}

	if (m_pbtmThumbDef != NULL) {
		BITMAP bm;
		m_pbtmThumbDef->GetObject(sizeof(bm), &bm);
		if (rectchn.Height() < rectchn.Width()) {
			thumbRect.left = rectchn.left + size - bm.bmWidth / 2;
			thumbRect.right = thumbRect.left + bm.bmWidth;
			thumbRect.top = (thumbRect.bottom - bm.bmHeight) / 2;
			thumbRect.bottom = thumbRect.top + bm.bmHeight;
		}
		else {
			thumbRect.left = (thumbRect.right - bm.bmWidth) / 2;
			thumbRect.right = thumbRect.left + bm.bmWidth;
			thumbRect.top = rectchn.top + size - bm.bmHeight / 2;
			thumbRect.bottom = thumbRect.top + bm.bmHeight;
		}
	}
	else {
		int tempSize;
		if (rectchn.Height() < rectchn.Width()) {
			tempSize = (thumbRect.right - thumbRect.left) / 2;
			thumbRect.left = size - tempSize + rectchn.left;
			thumbRect.right = size + tempSize + rectchn.left;
		}
		else {
			tempSize = (thumbRect.bottom - thumbRect.top) / 2;
			thumbRect.top = size - tempSize + rectchn.top;
			thumbRect.bottom = size + tempSize + rectchn.top;
		}
	}

	return thumbRect;
}

void CSkinSliderCtrl::setPointToPos(CPoint point)
{
	CRect rect;
	GetChannelRect(&rect);

	
	point.x = min(max(rect.left, point.x), rect.right);
	
	int size = 0;

	size = GetRangeMax() * (point.x - rect.left) / rect.Width();
		
	size = (size >= GetRangeMax())? GetRangeMax() - 1 : size;
	_SetPos(size);

	CSliderParam sp;
	sp.pThis = this;
	sp.llValue = size;

	GetParent()->SendMessage(MESSAGE_SLIDER_EVENT, SLIDER_BEFORE_MOVE, (LPARAM)&sp);
	

	::SendMessage(GetSafeHwnd(), WM_KILLFOCUS, NULL, NULL);
}

// Enables/Disables window borders
HRESULT CSkinSliderCtrl::_EnableBorders(BOOL bEnable/*=TRUE*/)
{
	m_bBorders = bEnable;
	int min,max;
	GetRange(min,max);
	CSliderCtrl::SetRange(min,max,TRUE);
	return S_OK;
}


BOOL CSkinSliderCtrl::_IsEnabled(void)
{
	return m_bBorders;
}

BOOL CSkinSliderCtrl::Freeze(void)
{	
	BOOL Prev= m_bFreezed;
	if(!Prev) // Freeze now
	{
		tmp1 = m_ThClDef;
		tmp2 = m_ProBkColor;
		SetTimer(WM_FREEZE,1000,NULL);
		m_bFreezed = TRUE;

	}
	else {
		KillTimer(WM_FREEZE);
		m_bFreezed = FALSE;
		m_ThClDef = tmp1;
		m_ProBkColor = tmp2;
		int min,max;
		GetRange(min,max);
		CSliderCtrl::SetRange(min,max,TRUE);
	}
	return Prev;
}

void CSkinSliderCtrl::SetFreeze(BOOL freeze)
{
	m_bFreezed = freeze;
}

void CSkinSliderCtrl::setThumbSkin(UINT imgOut, UINT imgOver)
{
	m_pbtmThumbOut = new CBitmap();
	m_pbtmThumbOut->LoadBitmap(imgOut);
	m_pbtmThumbDef = m_pbtmThumbOut;

	if (imgOver != -1) {
		m_pbtmThumbOver = new CBitmap();
		m_pbtmThumbOver->LoadBitmap(imgOver);
	}
}

void CSkinSliderCtrl::setProgressSkin(UINT img)
{
	m_pbtmProgress = new CBitmap();
	m_pbtmProgress->LoadBitmap(img);
}

void CSkinSliderCtrl::setBackground(UINT img)
{
	m_pbtmBackgrand = new CBitmap();
	m_pbtmBackgrand->LoadBitmap(img);
}

BOOL CSkinSliderCtrl::isDrag()
{
	return isLbuttonDown;
}

// used for freezing operation
void CSkinSliderCtrl::OnTimer(UINT nIDEvent)
{
	int min,max;
	if (m_bBlink) {
		m_ThClDef = RGB(102,102,204);
		m_bBlink = FALSE;
		m_ProBkColor = RGB(102,102,204);
		GetRange(min,max);
		CSliderCtrl::SetRange(min,max,TRUE);
	} 
	else {
		m_ThClDef = RGB(204,204,204);
		m_ProBkColor = RGB(204,204,204);
		GetRange(min,max);
		CSliderCtrl::SetRange(min,max,TRUE);			
		m_bBlink = TRUE;			
	}
	CSliderCtrl::OnTimer(nIDEvent);
}


void CSkinSliderCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
	if (m_bFreezed) {
		return;
	}
	isLbuttonDown = TRUE;
	setPointToPos(point);

	CSliderCtrl::OnLButtonDown(nFlags, point);	
}


void CSkinSliderCtrl::OnLButtonUp(UINT nFlags, CPoint point)
{
	CSliderCtrl::OnLButtonUp(nFlags, point);
	if (m_bFreezed) {
		return;
	}
	
	if (isLbuttonDown == TRUE) {
		//_SetPos(GetPos());

		int pos = GetPos();
		/*double size;

		size = pos * 0.044;
		pos += size;*/
		
		CSliderParam sp;
		sp.pThis = this;
		sp.llValue = pos;

		GetParent()->SendMessage(MESSAGE_SLIDER_EVENT, SLIDER_AFTER_MOVE, (LPARAM)&sp);
		OnSliderPosChange(pos);
		isLbuttonDown = FALSE;
	}	
}


void CSkinSliderCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	isKeyDown = TRUE;
	switch (nChar)
	{
	case VK_LEFT:
	case VK_DOWN:
		m_ProgressPos = GetPos() <= 0 ? 0 : GetPos() - GetLineSize();
		Invalidate(FALSE);
		break;

	case VK_RIGHT:
	case VK_UP:
		m_ProgressPos = GetPos() >= GetRangeMax() ? GetRangeMax() - 1 : GetPos() + GetLineSize();
		Invalidate(FALSE);
		break;

	default:
		break;
	}
		
	CSliderCtrl::OnKeyDown(nChar, nRepCnt, nFlags);
}


void CSkinSliderCtrl::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	isKeyDown = FALSE;
	switch (nChar)
	{
	case VK_LEFT:
	case VK_RIGHT:
	case VK_UP:
	case VK_DOWN:
		CSliderParam sp;
		sp.pThis = this;
		sp.llValue = GetPos();

		GetParent()->SendMessage(MESSAGE_SLIDER_EVENT, SLIDER_AFTER_MOVE, (LPARAM)&sp);
		Invalidate(FALSE);
		break;

	default:
		break;
	}

	CSliderCtrl::OnKeyUp(nChar, nRepCnt, nFlags);
}


BOOL CSkinSliderCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{	
	return TRUE;
}
Comments