/////////////////////////////////////////////////////////////////////////////
// DropWnd.cpp : implementation file
// 
// CAdvComboBox Control
// Version: 2.1
// Date: September 2002
// Author: Mathias Tunared
// Email: Mathias@inorbit.com
// Copyright (c) 2002. All Rights Reserved.
//
// This code, in compiled form or as source code, may be redistributed 
// unmodified PROVIDING it is not sold for profit without the authors 
// written consent, and providing that this notice and the authors name 
// and all copyright notices remains intact.
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability for any damage/loss of business that
// this product may cause.
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "DropWnd.h"
#include "AdvComboBox.h"
#include "DropListBox.h"
#include "VisualStylesXP.h"

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

/////////////////////////////////////////////////////////////////////////////
// CDropWnd

CDropWnd::CDropWnd( CWnd* pComboParent, list<LIST_ITEM> &itemlist, DWORD dwACBStyle )
:
	m_pComboParent( pComboParent ),
	m_list( itemlist ),
	m_dwACBStyle( dwACBStyle ),
	m_nMaxX(1000),	//+++
	m_nMaxY(1000)	//+++
{
	m_bResizing = false;

	m_pListFont = new CFont;
	LOGFONT logFont;
	memset( &logFont, 0, sizeof(LOGFONT) );
	_tcscpy( logFont.lfFaceName, _T("MS Sans Serif") );
	logFont.lfHeight = 12;
	m_pListFont->CreateFontIndirect(&logFont);
}

CDropWnd::~CDropWnd()
{
	delete m_pListFont;
	delete m_scrollbar;
	delete m_listbox;
}

BEGIN_MESSAGE_MAP(CDropWnd, CWnd)
	//{{AFX_MSG_MAP(CDropWnd)
	ON_WM_CREATE()
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONDOWN()
	ON_WM_SIZE()
	ON_WM_PAINT()
	ON_WM_LBUTTONUP()
	ON_WM_SHOWWINDOW()
	ON_WM_ACTIVATEAPP()
	ON_WM_ERASEBKGND()
	//}}AFX_MSG_MAP
	ON_MESSAGE( WM_VRC_SETCAPTURE, OnSetCapture )
	ON_MESSAGE( WM_VRC_RELEASECAPTURE, OnReleaseCapture )
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CDropWnd message handlers

BOOL CDropWnd::PreCreateWindow(CREATESTRUCT& cs) 
{
	//
	// Calc the size of the wnd
	
	return CWnd::PreCreateWindow(cs);
}

#if 0  // -----------------------------------------------------------
BOOL CDropWnd::Create(DWORD dwStyle, 
					  const RECT& rect, 
					  CWnd* pParentWnd, 
					  UINT nID, 
					  CCreateContext* pContext) 
{
	return CWnd::Create(0, 0, dwStyle, rect, pParentWnd, nID, pContext);
}
#endif // -----------------------------------------------------------

int CDropWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CWnd::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	CRect rcWnd;
	GetClientRect( &rcWnd );

	//
	// Because this window doesn't have an owner, there will appear 
	// a 'blank' button on the taskbar. The following are to hide 
	// that 'blank' button on the taskbar
	ModifyStyleEx( 0, WS_EX_TOOLWINDOW );
	SetWindowPos( &wndTopMost, lpCreateStruct->x, lpCreateStruct->y, 
		lpCreateStruct->cx, lpCreateStruct->cy, SWP_SHOWWINDOW );

	//
	// Create scrollbar
	m_rcScroll = rcWnd;
	m_rcScroll.left = m_rcScroll.right - ::GetSystemMetrics(SM_CXVSCROLL);
	m_rcScroll.bottom -= ::GetSystemMetrics(SM_CYVSCROLL);
	m_scrollbar = new CDropScrollBar;
	VERIFY(m_scrollbar->Create( SBS_VERT | SBS_RIGHTALIGN | WS_CHILD, m_rcScroll, this, 100));

	//
	// Create listbox
	m_rcList.SetRect( lpCreateStruct->x, lpCreateStruct->y, 
		lpCreateStruct->x+lpCreateStruct->cx-::GetSystemMetrics(SM_CXVSCROLL), 
		lpCreateStruct->y+lpCreateStruct->cy );
	ScreenToClient( m_rcList );
	m_listbox = new CDropListBox(m_pComboParent, m_scrollbar);
	VERIFY(m_listbox->Create( WS_CHILD | LBS_NOINTEGRALHEIGHT 
		/*| WS_VISIBLE | */ /*| LBS_OWNERDRAWFIXED*/, 
		m_rcList, this, 101 ) );
	m_listbox->SetDLBStyle( m_dwACBStyle );
	m_listbox->ShowWindow( SW_SHOW );

	//
	// Resize this wnd so INTEGRAL_HEIGHT applies!?
	CRect rc;
	int nH = m_listbox->GetItemHeight(0);
	nH = nH*m_list.size()+2;
	// Get screen size
	int nScrX = GetSystemMetrics( SM_CXSCREEN );
	int nScrY = GetSystemMetrics( SM_CYSCREEN );

	int nDefaultItems = static_cast<CAdvComboBox*>(m_pComboParent)->GetDefaultVisibleItems();

	//
	// Check to see if the window should be placed over the combobox
	int nY = lpCreateStruct->y;
	int nItems = m_list.size();
	int nItemHeight = m_listbox->GetItemHeight(0);
	int nVisHeight = nScrY - lpCreateStruct->y;
	CRect rcCombo;
	m_pComboParent->GetWindowRect( &rcCombo );
	if( (nVisHeight / nItemHeight) < static_cast<CAdvComboBox*>(m_pComboParent)->GetMinVisibleItems() )
	{
		int nComboTopY = lpCreateStruct->y - rcCombo.Height();
		if( nDefaultItems == -1 || nDefaultItems > nItems )
		{
			nY = (nComboTopY - nH) < 0 ? 0 : (nComboTopY - nH);
			nH = (nY + nH) > nComboTopY ? nComboTopY - nY : nH;
		}
		else
		{
			nY = nComboTopY - nItemHeight*nDefaultItems;
			nY -= 2;
			nY = nY < 0 ? 0 : nY;
			nH = nComboTopY - nY;
		}
	}
	else
	{
		//
		// Place the window below the combo
		// Check height
		if( nDefaultItems == -1 || nDefaultItems > nItems )
		{
			if( lpCreateStruct->y + nH > nScrY )
			{
				nH = nScrY - lpCreateStruct->y;
			}
			else
			if( nH < ::GetSystemMetrics(SM_CYVSCROLL) )
			{
				nH = ::GetSystemMetrics(SM_CYVSCROLL);
			}
		}
		else
		{
			nH = nDefaultItems * nItemHeight;
			nH = (nY+nH) > nScrY ? nScrY-nY : nH;
			nH += 2;
		}
	}

	// Calc width
	int nW = 0;
	CSize size(0,0);
	for( m_iter = m_list.begin(); m_iter != m_list.end(); ++m_iter )
	{
		m_listbox->GetTextSize( m_iter->strText.c_str(), m_iter->strText.length(), size );
		nW = (size.cx > nW) ? size.cx : nW;
	}

	nW += m_rcScroll.Width() + 8;

	// Check min width
	if( nW < m_rcList.Width() )
	{
		nW = lpCreateStruct->cx;
	}

	//+++
	if (nW < rcCombo.Width())
		nW = rcCombo.Width();

	// Check max width
	int nX = lpCreateStruct->x;
	if( nW > nScrX - lpCreateStruct->x )
	{
		nX = nScrX - nW;
		if( nX < 0 )
			nX = 0;
	}
	if( nX == 0 && nW > nScrX )
		nW = nScrX;

	//nW += 4;			//+++
	m_nMaxX = nW + 100;	//+++
	m_nMaxY = nH + 100;	//+++

	SetWindowPos( &wndTopMost, nX, nY, nW, nH, SWP_SHOWWINDOW|SWP_NOZORDER );

	GetClientRect( &rcWnd );

	//
	// Create sizehandle
	m_rcSizeHandle = rcWnd;
	GetClientRect( &m_rcSizeHandle );
	m_rcSizeHandle.left = m_rcSizeHandle.right - ::GetSystemMetrics(SM_CXVSCROLL);
	m_rcSizeHandle.top = m_rcSizeHandle.bottom - ::GetSystemMetrics(SM_CYVSCROLL);

	//
	// Add items to listbox
	LIST_ITEM item;
	for( m_iter = m_list.begin(); m_iter != m_list.end(); ++m_iter )
	{
		item = *m_iter;
		m_listbox->AddListItem( item );
	}

	//
	// Set values in scrollbar
	m_scrollbar->SetListBox( m_listbox );
	m_scrollbar->ShowScrollBar();

	//
	//
	SetCapture();
	return 0;
}

LONG CDropWnd::OnSetCapture( WPARAM /*wParam*/, LPARAM /*lParam*/ )
{
	SetCapture();
	return FALSE;
}

LONG CDropWnd::OnReleaseCapture( WPARAM /*wParam*/, LPARAM /*lParam*/ )
{
	ReleaseCapture();
	return FALSE;
}

void CDropWnd::OnMouseMove(UINT nFlags, CPoint point) 
{
	//
	//
	if( m_bResizing )
	{
		CRect rcWnd;
		GetWindowRect( &rcWnd );
#if 0  // -----------------------------------------------------------
		if( point.x + m_nMouseDiffX >= ::GetSystemMetrics(SM_CXVSCROLL) )
		{
			rcWnd.right = rcWnd.left + point.x + m_nMouseDiffX +2;
		}
		else
		{
			rcWnd.right = rcWnd.left + ::GetSystemMetrics(SM_CXVSCROLL) +1;
		}

		if( point.y + m_nMouseDiffY >= ::GetSystemMetrics(SM_CYVSCROLL) )
		{
			rcWnd.bottom = rcWnd.top + point.y + m_nMouseDiffY +2;
		}
		else
		{
			rcWnd.bottom = rcWnd.top + ::GetSystemMetrics(SM_CXVSCROLL) +1;
		}
#endif // -----------------------------------------------------------

		//+++
		CRect rcCombo;
		m_pComboParent->GetWindowRect( &rcCombo );

		if( point.x + m_nMouseDiffX < rcCombo.Width())
		{
			rcWnd.right = rcWnd.left + rcCombo.Width();
		}
		else if (point.x + m_nMouseDiffX > m_nMaxX)
		{
			rcWnd.right = rcWnd.left + m_nMaxX;
		}
		else
		{
			rcWnd.right = rcWnd.left + point.x + m_nMouseDiffX;
		}

		if( point.y + m_nMouseDiffY < :: GetSystemMetrics(SM_CYVSCROLL) )
		{
			rcWnd.bottom = rcWnd.top + ::GetSystemMetrics(SM_CXVSCROLL) +1;
		}
		else if ( point.y + m_nMouseDiffY > m_nMaxY )
		{
			rcWnd.bottom = rcWnd.top + m_nMaxY;
		}
		else
		{
			rcWnd.bottom = rcWnd.top + point.y + m_nMouseDiffY +2;
		}


		MoveWindow( &rcWnd );
		return;
	}

	//
	// Check point
	if( m_rcList.PtInRect( point ) )
	{
		HCURSOR hCursor = LoadCursor( NULL, IDC_ARROW );
		SetCursor( hCursor );
		ReleaseCapture();
		m_scrollbar->SendMessage( WM_VRC_RELEASECAPTURE );
		m_listbox->SetFocus();
		m_listbox->SendMessage( WM_VRC_SETCAPTURE );
	}
	else
	if( m_rcScroll.PtInRect( point ) )
	{
		HCURSOR hCursor = LoadCursor( NULL, IDC_ARROW );
		SetCursor( hCursor );
		m_scrollbar->SetFocus();
		ReleaseCapture();
		m_listbox->SendMessage( WM_VRC_RELEASECAPTURE );
		m_scrollbar->SendMessage( WM_VRC_SETCAPTURE );
	}
	else
	{
		if( m_rcSizeHandle.PtInRect( point ) )
		{
			HCURSOR hCursor = LoadCursor( NULL, IDC_SIZENWSE );
			SetCursor( hCursor );
		}
		else
		{
			HCURSOR hCursor = LoadCursor( NULL, IDC_ARROW );
			SetCursor( hCursor );
		}
		SetCapture();
		CWnd::OnMouseMove(nFlags, point);
	}
}

void CDropWnd::OnLButtonDown(UINT nFlags, CPoint point) 
{
	if( m_rcSizeHandle.PtInRect( point ) )
	{
		m_bResizing = true;

		m_ptLastResize = point;

		CRect rcClient;
		GetClientRect( &rcClient );
		m_nMouseDiffX = rcClient.Width() - point.x;
		m_nMouseDiffY = rcClient.Height() - point.y;
		return;
	}

//
// Clean up the code below...
//

	CRect rc;
	CRect rcVScroll(0,0,0,0);
	GetClientRect( &rc );
	
	// Take away vertical scroll

	if( rc.PtInRect( point ) )
	{
	}
	else
	{
		//
		// Calc the point in the parent(PropertyListBox)
		CWnd* pParent = m_pComboParent->GetParent();
		CRect rcParentClient;
		CRect rcParentWnd;
		pParent->GetClientRect( &rcParentClient );
		pParent->GetWindowRect( &rcParentWnd );

		CPoint pt = point;
		ClientToScreen( &pt );
			pt.x -= rcParentWnd.left;
			pt.y -= rcParentWnd.top;

		CAdvComboBox* pList = static_cast<CAdvComboBox*>(m_pComboParent);
		if( !pList->PointInWindow( pt ) )
		{
			
			ReleaseCapture();

			m_pComboParent->PostMessage( WM_DESTROY_DROPLIST );
		}
		else
		{
			ReleaseCapture();
			m_pComboParent->PostMessage( WM_DESTROY_DROPLIST );
		}
	}

	LPARAM l = MAKELPARAM(point.x, point.y);
	m_pComboParent->SendMessage(WM_LBUTTONDOWN, nFlags, l);

	CWnd::OnLButtonDown(nFlags, point);
}

void CDropWnd::OnLButtonUp(UINT nFlags, CPoint point) 
{
	if( m_bResizing )
	{
		m_bResizing = false;
		m_listbox->UnlockWindowUpdate();

		m_listbox->RedrawWindow();
	}
	CWnd::OnLButtonUp(nFlags, point);
}

void CDropWnd::OnSize(UINT nType, int cx, int cy) 
{
	CWnd::OnSize(nType, cx, cy);

	m_rcList.SetRect( 0, 0, cx-::GetSystemMetrics(SM_CXVSCROLL), cy );
	CRect rectBorder = m_rcList;
	m_rcList.DeflateRect(1, 1);
	m_listbox->MoveWindow( &m_rcList );

	m_rcScroll.SetRect( cx-::GetSystemMetrics(SM_CXVSCROLL), 0, cx, cy-::GetSystemMetrics(SM_CYVSCROLL) );
	m_rcScroll.DeflateRect(1, 1);
	m_scrollbar->MoveWindow( &m_rcScroll );

	//?????  +++
	rectBorder.right = m_rcScroll.right + 1;
	//CPen pen(PS_SOLID, 1, ::GetSysColor(COLOR_BTNSHADOW));//COLOR_INACTIVECAPTION));	// same as combobox
	CPen pen(PS_SOLID, 1, ::GetSysColor(COLOR_3DDKSHADOW));//COLOR_INACTIVECAPTION));	// same as combobox
	CDC * pDC = GetDC();
	CPen *pOldPen = pDC->SelectObject(&pen);
	pDC->Rectangle(&rectBorder);
	pDC->SelectObject(pOldPen);
	ReleaseDC(pDC);

	m_rcSizeHandle.SetRect( cx-::GetSystemMetrics(SM_CXVSCROLL), cy-::GetSystemMetrics(SM_CYVSCROLL), cx, cy );
	m_rcSizeHandle.DeflateRect(1, 1);
	InvalidateRect( &m_rcSizeHandle );

	//
	// Fix the scrollbar
	SCROLLINFO info;
	info.cbSize = sizeof(SCROLLINFO);
	if( m_scrollbar->GetScrollInfo( &info, SIF_ALL|SIF_DISABLENOSCROLL ) )
	{
		info.nPage = m_listbox->GetBottomIndex() - m_listbox->GetTopIndex();
		m_scrollbar->SetScrollInfo( &info );
	}
}

void CDropWnd::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
	
	if( g_xpStyle.UseVisualStyles() )
	{
		HTHEME hTheme = NULL;
		hTheme = g_xpStyle.OpenThemeData( m_hWnd, L"SCROLLBAR" );
		HRESULT hr = g_xpStyle.DrawThemeBackground( hTheme, dc.m_hDC, SBP_LOWERTRACKVERT, SCRBS_NORMAL, &m_rcSizeHandle, NULL);
		hr = g_xpStyle.DrawThemeBackground( hTheme, dc.m_hDC, SBP_SIZEBOX, SZB_RIGHTALIGN, &m_rcSizeHandle, NULL);
		hr = g_xpStyle.CloseThemeData( hTheme );

	}
	else
	{
		dc.DrawFrameControl(m_rcSizeHandle, DFC_SCROLL, DFCS_SCROLLSIZEGRIP );
	}

	// Do not call CWnd::OnPaint() for painting messages
}


BOOL CDropWnd::DestroyWindow() 
{
	ReleaseCapture();
	m_listbox->DestroyWindow();
	
	return CWnd::DestroyWindow();
}

void CDropWnd::OnShowWindow(BOOL bShow, UINT nStatus) 
{
	CWnd::OnShowWindow(bShow, nStatus);
	
	if( bShow )
	{
//		AnimateWindow( GetSafeHwnd(), 80, AW_VER_POSITIVE | AW_ACTIVATE | AW_SLIDE);
	}
	else
	{
//		AnimateWindow( GetSafeHwnd(), 80, AW_VER_NEGATIVE | AW_HIDE | AW_SLIDE);
	}
	
}

//+++
#if (_MSC_VER > 1200)
void CDropWnd::OnActivateApp(BOOL bActive, DWORD dwThreadID) 
{
	CWnd::OnActivateApp(bActive, dwThreadID);
#else
 void CDropWnd::OnActivateApp(BOOL bActive, HTASK hTask) 
{
	CWnd::OnActivateApp(bActive, hTask);
#endif

	if(!bActive) 
	{
		m_pComboParent->PostMessage(WM_DESTROY_DROPLIST);
	}
}

