/*
===========================================================================

Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.

This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").

Doom 3 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.

Doom 3 Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.

In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.

If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.

===========================================================================
*/
#include "tools/edit_gui_common.h"


#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) {
	float scaling_factor = Win_GetWindowScalingFactor(GetSafeHwnd());
	lpMeasureItemStruct->itemHeight = TOGGLELIST_ITEMHEIGHT * scaling_factor;
}

/**
* 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, 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 );
}
