/*****************************************************************************
The Dark Mod GPL Source Code

This file is part of the The Dark Mod Source Code, originally based
on the Doom 3 GPL Source Code as published in 2011.

The Dark Mod Source Code is free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of the License,
or (at your option) any later version. For details, see LICENSE.TXT.

Project: The Dark Mod (http://www.thedarkmod.com/)

******************************************************************************/
#include "precompiled.h"
#pragma hdrstop



#if defined(ID_DEBUG_MEMORY) && defined(ID_REDIRECT_NEWDELETE)
#undef new
#undef DEBUG_NEW
#define DEBUG_NEW new
#endif
#ifdef ID_USE_TYPEINFO
#undef protected
#endif

#include "ToggleListView.h"

#define TOGGLELIST_ITEMHEIGHT 22
#define TEXT_OFFSET 6


IMPLEMENT_DYNCREATE(ToggleListView, CListView)

BEGIN_MESSAGE_MAP(ToggleListView, CListView)
	ON_WM_CREATE()
	ON_WM_SIZE()
	ON_WM_MEASUREITEM_REFLECT()
	ON_NOTIFY_REFLECT(NM_CLICK, OnNMClick)
END_MESSAGE_MAP()


/**
* Protected constructor used by dynamic creation.
*/
ToggleListView::ToggleListView() {
	onIcon = NULL;
	offIcon = NULL;
	disabledIcon = NULL;
}

/**
* Destructor.
*/
ToggleListView::~ToggleListView() {
}


/**
* Sets the tree icons to dispay for each of the three states. Sets the 
* icons to display for each of the three states. The values passed in 
* are the resource name that can be generated using MAKEINTRESOUCE. If 
* the value passed in is NULL then an icon will not be drawn for that
* state.
* @param disabled The icon to draw when the state is TOGGLE_STATE_DISABLED.
* @param on The icon to draw when the state is TOGGLE_STATE_ON.
* @param off The icon to draw when the state is TOGGLE_STATE_OFF.
*/
void ToggleListView::SetToggleIcons(LPCSTR disabled, LPCSTR on, LPCSTR off) {
	if(on) {
		onIcon = (HICON)LoadImage ( AfxGetInstanceHandle(), on, IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR|LR_LOADMAP3DCOLORS );
	} else {
		onIcon = NULL;
	}

	if(off) {
		offIcon = (HICON)LoadImage ( AfxGetInstanceHandle(), off, IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR|LR_LOADMAP3DCOLORS );
	} else {
		offIcon = NULL;
	}

	if(disabled) {
		disabledIcon = (HICON)LoadImage ( AfxGetInstanceHandle(), disabled, IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR|LR_LOADMAP3DCOLORS );
	} else {
		disabledIcon = NULL;
	}
}

/**
* Sets the state of an item in the list.
* @param index Index of the item whose state should be changed.
* @param toggleState The state to set
* @param notify Determines if the notification method OnStateChanged should
* be called. OnStateChanged will also not be called if the state has not changed.
*/
void ToggleListView::SetToggleState(int index, int toggleState, bool notify) {
	CListCtrl& list = GetListCtrl();
	assert(index >= 0 && index < list.GetItemCount());

	int oldState = GetToggleState(index);
	list.SetItemData(index, toggleState);

	if(notify && oldState != toggleState)
		OnStateChanged(index, toggleState);
}

/**
* Gets the state of an item in the list
* @param index Index of the item of which to retreive the state.
*/
int ToggleListView::GetToggleState(int index) {
	CListCtrl& list = GetListCtrl();
	assert(index >= 0 && index < list.GetItemCount());

	DWORD data = list.GetItemData(index);
	return data;
}

/**
* Called as the window is being created and initializes icons and window styles
*/
int ToggleListView::OnCreate(LPCREATESTRUCT lpCreateStruct) {
	if (CListView::OnCreate(lpCreateStruct) == -1)
		return -1;

	CListCtrl& list = GetListCtrl();
	
	list.SetExtendedStyle(LVS_EX_FULLROWSELECT);

	//Turn off the horizontal scroll bar
	//Todo: Figure out why the damn scroll bar pops up
	list.ModifyStyle(WS_HSCROLL, 0L);
	
	
	//Insert the one column
	LVCOLUMN col;
	col.mask = 0;
	list.InsertColumn(0, &col);

	SetToggleIcons();
	
	return 0;
}

/**
* Called when the window is being resized.
*/
void ToggleListView::OnSize(UINT nType, int cx, int cy) {
	CListView::OnSize(nType, cx, cy);

	CListCtrl& list = GetListCtrl();
	list.SetColumnWidth(0, cx-1);
}

/**
* Returns the size of each item in the toggle list.
*/
void ToggleListView::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) {
	lpMeasureItemStruct->itemHeight = TOGGLELIST_ITEMHEIGHT;	
}

/**
* Toggles the state of an item when the user clicks in the window.
*/
void ToggleListView::OnNMClick(NMHDR *pNMHDR, LRESULT *pResult) {
	CListCtrl& list = GetListCtrl();

	DWORD dwpos = GetMessagePos(); 

	LVHITTESTINFO info;
	info.pt.x = LOWORD(dwpos);
	info.pt.y = HIWORD(dwpos);		

	::MapWindowPoints(HWND_DESKTOP, pNMHDR->hwndFrom, &info.pt, 1);      

	int index = list.HitTest(&info);
	if ( index != -1 ) {
		int toggleState = GetToggleState(index);
		if(toggleState != TOGGLE_STATE_DISABLED) {

			RECT	rItem;
			list.GetItemRect(index, &rItem, LVIR_BOUNDS);

			if ( info.pt.x < TOGGLELIST_ITEMHEIGHT ) {
				if(toggleState == TOGGLE_STATE_ON) {
					SetToggleState(index, TOGGLE_STATE_OFF, true);
				} else {
					SetToggleState(index, TOGGLE_STATE_ON, true);
				}
			}												
		}
	}
	*pResult = 0;
}

/**
* Sets some window styles before the window is created.
*/
BOOL ToggleListView::PreCreateWindow(CREATESTRUCT& cs) {
	//Set the required style for the toggle view
	cs.style &= ~LVS_TYPEMASK;
	cs.style |= LVS_REPORT | LVS_OWNERDRAWFIXED | LVS_NOCOLUMNHEADER | LVS_SHOWSELALWAYS;

	return CListView::PreCreateWindow(cs);
}

/**
* Responsible for drawing each list item.
*/
void ToggleListView::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) {

	CListCtrl& ListCtrl=GetListCtrl();
	int nItem = lpDrawItemStruct->itemID;
	
	// get item data
	LV_ITEM lvi;
	_TCHAR szBuff[MAX_PATH];
	
	memset(&lvi, 0, sizeof(LV_ITEM));
	lvi.mask = LVIF_TEXT;
	lvi.iItem = nItem;
	lvi.pszText = szBuff;
	lvi.cchTextMax = sizeof(szBuff);
	ListCtrl.GetItem(&lvi);

	RECT rDraw;
	
	
	CopyRect ( &rDraw, &lpDrawItemStruct->rcItem );
	rDraw.right = rDraw.left + TOGGLELIST_ITEMHEIGHT;
	rDraw.top ++;

	rDraw.right ++;
	FrameRect ( lpDrawItemStruct->hDC, &rDraw, (HBRUSH)GetStockObject ( BLACK_BRUSH ) );
	rDraw.right --;

	FillRect ( lpDrawItemStruct->hDC, &rDraw, GetSysColorBrush ( COLOR_3DFACE ) );

	Draw3dRect ( lpDrawItemStruct->hDC, &rDraw, GetSysColorBrush ( COLOR_3DHILIGHT ), GetSysColorBrush ( COLOR_3DSHADOW ) );

	InflateRect ( &rDraw, -3, -3 );
	Draw3dRect ( lpDrawItemStruct->hDC, &rDraw, GetSysColorBrush ( COLOR_3DSHADOW ), GetSysColorBrush ( COLOR_3DHILIGHT ) );

	switch(GetToggleState(lvi.iItem)) {
		case TOGGLE_STATE_DISABLED:
			if(disabledIcon) {
				DrawIconEx ( lpDrawItemStruct->hDC, rDraw.left, rDraw.top, disabledIcon, 16, 16,0, NULL, DI_NORMAL );
			}
			break;
		case TOGGLE_STATE_ON:
			if(onIcon) {
				DrawIconEx ( lpDrawItemStruct->hDC, rDraw.left, rDraw.top, onIcon, 16, 16,0, NULL, DI_NORMAL );
			}
			break;
		case TOGGLE_STATE_OFF:
			if(offIcon) {
				DrawIconEx ( lpDrawItemStruct->hDC, rDraw.left, rDraw.top, offIcon, 16, 16,0, NULL, DI_NORMAL );
			}
			break;
	};
	
	CopyRect ( &rDraw, &lpDrawItemStruct->rcItem );
	rDraw.left += TOGGLELIST_ITEMHEIGHT;
	rDraw.left += 1;

	if ( lpDrawItemStruct->itemState & ODS_SELECTED ) {
		FillRect ( lpDrawItemStruct->hDC, &rDraw, GetSysColorBrush ( COLOR_HIGHLIGHT ) );			
	} else {
		FillRect ( lpDrawItemStruct->hDC, &rDraw, GetSysColorBrush ( COLOR_WINDOW ) ); 
	}

	rDraw.left += TEXT_OFFSET;

	int colorIndex = ( (lpDrawItemStruct->itemState & ODS_SELECTED ) ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT );
	SetTextColor ( lpDrawItemStruct->hDC, GetSysColor ( colorIndex ) );
    DrawText(lpDrawItemStruct->hDC, szBuff, static_cast<int>(strlen(szBuff)), &rDraw, DT_LEFT | DT_VCENTER | DT_SINGLELINE);

}


/**
* Draws a 3d rectangle using the given brushes this code was taken from the gui editor
*/
void ToggleListView::Draw3dRect (HDC hDC, RECT* rect, HBRUSH topLeft, HBRUSH bottomRight) {
	RECT rOut;

	SetRect ( &rOut, rect->left, rect->top, rect->right - 1, rect->top + 1 );
	FillRect ( hDC,&rOut, topLeft ); 

	SetRect ( &rOut, rect->left, rect->top, rect->left + 1, rect->bottom );
	FillRect( hDC,&rOut, topLeft ); 

	SetRect ( &rOut, rect->right, rect->top, rect->right -1, rect->bottom  );
	FillRect( hDC,&rOut, bottomRight ); 

	SetRect ( &rOut, rect->left, rect->bottom, rect->right, rect->bottom - 1 );
	FillRect( hDC,&rOut, bottomRight ); 
}




