/*
Quick Messages plugin for Miranda IM
Copyright (C) 2008 Danil Mozhar
This program 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.
This program 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 this program.  If not, see .
*/
#include "quickmessages.h"
int g_iOPButtonsCount;
BOOL bNeedRestart = FALSE;
BOOL drag = FALSE, bOptionsInit = TRUE;
HTREEITEM hDragItem = NULL;
HWND hButtonsList = NULL;
HWND hMenuTree = NULL;
HWND hwndEdit = NULL;
WNDPROC oldEditProc = 0, oldBNameProc = 0, oldMNameProc = 0;
				   
HWND g_opHdlg = NULL, g_varhelpDlg = NULL;
INT_PTR CALLBACK HelpDlgProc(HWND hdlg,UINT msg,WPARAM wparam,LPARAM lparam)
	{	
	switch(msg){
		case WM_INITDIALOG:{
			LOGFONT logFont;
			HFONT hFont;
			RECT rc;
			g_varhelpDlg=hdlg;
			TranslateDialogDefault(hdlg); 
			hFont = (HFONT)SendMessage(GetDlgItem(hdlg, IDC_STATICTITLE), WM_GETFONT, 0, 0);
			GetObject(hFont, sizeof logFont, &logFont);
			logFont.lfWeight = FW_BOLD;
			hFont = CreateFontIndirect(&logFont);
			SendMessage(GetDlgItem(hdlg, IDC_STATICTITLE), WM_SETFONT, (WPARAM)hFont, 0);
			SendMessage(GetDlgItem(hdlg, IDC_STATICTITLE2), WM_SETFONT, (WPARAM)hFont, 0);
			SendMessage(GetDlgItem(hdlg, IDC_VARTEXT), WM_SETFONT, (WPARAM)hFont, 0);
			SendMessage(GetDlgItem(hdlg, IDC_VARCLIP), WM_SETFONT, (WPARAM)hFont, 0);
			SendMessage(GetDlgItem(hdlg, IDC_VARPUNAME), WM_SETFONT, (WPARAM)hFont, 0);
			SendMessage(GetDlgItem(hdlg, IDC_VARPLNAME), WM_SETFONT, (WPARAM)hFont, 0);
			SendMessage(GetDlgItem(hdlg, IDC_VARCNAME), WM_SETFONT, (WPARAM)hFont, 0);
			SendMessage(GetDlgItem(hdlg, IDC_VARCFNAME), WM_SETFONT, (WPARAM)hFont, 0);
			SendMessage(GetDlgItem(hdlg, IDC_VARCLNAME), WM_SETFONT, (WPARAM)hFont, 0);
			
			GetWindowRect(g_opHdlg,&rc);
			SetWindowPos(hdlg,0,rc.left,rc.top,0,0,SWP_SHOWWINDOW|SWP_NOSIZE);
			}break;
		case WM_LBUTTONDOWN:{
			PostMessage( hdlg,WM_NCLBUTTONDOWN, HTCAPTION,lparam);
			}break;
		case WM_CLOSE:
		case WM_DESTROY:
			DestroyWindow(g_varhelpDlg);
			g_varhelpDlg=NULL;
			break;
		default:
			return FALSE;
		}
	return TRUE;
	}
static LRESULT CALLBACK LabelEditSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
	{
	switch (msg) {
		case WM_GETDLGCODE:
			return DLGC_WANTALLKEYS;
		} 
	return CallWindowProc(oldEditProc, hwnd, msg, wParam, lParam);
	}
static LRESULT CALLBACK EditSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
	{
	HWND hParent=GetParent(hwnd);
	switch (msg) {
  		case WM_GETDLGCODE:
  			return DLGC_WANTALLKEYS|DLGC_HASSETSEL;
		case WM_SETFOCUS:
			PostMessage(hwnd,EM_SETSEL,0,-1);
			break;
		case WM_KEYDOWN:
			{
			if(wParam==VK_RETURN)
				if(hwnd==GetDlgItem(hParent,IDC_BUTTONNAME))
					SendMessage(hParent,WM_COMMAND,IDC_BLISTADD,0);
				else 
					SendMessage(hParent,WM_COMMAND,IDC_MTREEADD,0);
			}break;
		} 
	if(hwnd==GetDlgItem(hParent,IDC_BUTTONNAME))
		return CallWindowProc(oldBNameProc, hwnd, msg, wParam, lParam);
	else 
		return CallWindowProc(oldMNameProc, hwnd, msg, wParam, lParam);
	}
void SetMenuEntryProperties(HWND hdlg)
	{
	TVITEM tvi;
	HTREEITEM hItem=NULL;
	ButtonData* bd=NULL;
	int pos=0;
	if(TreeView_GetCount(hButtonsList)&&(tvi.hItem=TreeView_GetSelection(hButtonsList)))
		{
		tvi.mask=TVIF_HANDLE|TVIF_PARAM;
		TreeView_GetItem(hButtonsList,&tvi);
		if (tvi.lParam)
			{
			ListData* ld = ( ListData* )tvi.lParam;
			TCHAR szValue[256];
			GetWindowText(GetDlgItem(hdlg,IDC_RCLICKVALUE), szValue, sizeof(szValue));
			if(_tcslen(szValue))
				{
				if(ld->ptszOPQValue&&(ld->ptszOPQValue!=ld->ptszQValue))
					mir_free(ld->ptszOPQValue);
				ld->ptszOPQValue=mir_tstrdup(szValue);
				}
			ld->bIsOpServName=IsDlgButtonChecked(hdlg,IDC_ISSERVNAME2);
			}
		}
	tvi.hItem=NULL;
	if(TreeView_GetCount(hMenuTree)&&(tvi.hItem=TreeView_GetSelection(hMenuTree)))
		{
		tvi.mask=TVIF_HANDLE|TVIF_PARAM;
		TreeView_GetItem(hMenuTree,&tvi);
		if (tvi.lParam)
			{
			ButtonData* bd = ( ButtonData* )tvi.lParam;
			TCHAR szValue[256];
			GetWindowText(GetDlgItem(hdlg,IDC_MENUVALUE), szValue, sizeof(szValue));
			if(_tcslen(szValue))
				{
				if(_tcslen(bd->pszOpValue)&&(bd->pszOpValue!=bd->pszValue))
					mir_free(bd->pszOpValue);
				bd->pszOpValue=mir_tstrdup(szValue);
				}
			bd->bOpInQMenu=IsDlgButtonChecked(hdlg,IDC_INQMENU);
			bd->bIsOpServName=IsDlgButtonChecked(hdlg,IDC_ISSERVNAME);
			}
		
		tvi.mask = TVIF_HANDLE | TVIF_PARAM;
		tvi.hItem = TreeView_GetRoot(hMenuTree);
		}
		while (tvi.hItem) {
			TreeView_GetItem(hMenuTree, &tvi);
			bd= (ButtonData*)tvi.lParam;
			bd->dwOPPos=pos++;
			if(hItem=TreeView_GetChild(hMenuTree, tvi.hItem)) {
				bd->fEntryOpType&=~QMF_EX_CHILD;
				if(bd->pszOpValue){
					mir_free(bd->pszOpValue);
					bd->pszOpValue=NULL;
					}
				tvi.hItem=hItem;
				continue;
				}
			else 
				{
				if(bd->fEntryOpType&QMF_EX_SEPARATOR){
					if(bd->pszOpValue){
						mir_free(bd->pszOpValue);
						bd->pszOpValue=NULL;
						}}
				else
					{
					if (!bd->pszOpValue)
						bd->pszOpValue=mir_tstrdup(LPGENT("Enter Value"));
					}
					if(TreeView_GetParent(hMenuTree, tvi.hItem))
						bd->fEntryOpType|=QMF_EX_CHILD;
					else bd->fEntryOpType&=~QMF_EX_CHILD;
					if (!(hItem=TreeView_GetNextSibling(hMenuTree, tvi.hItem)))
						tvi.hItem=TreeView_GetNextSibling(hMenuTree, TreeView_GetParent(hMenuTree,tvi.hItem));
					else 
						tvi.hItem=hItem;
					
				}
			}
	}
void SaveMenuTree(HWND hdlg)
	{
	int iBl=0,i=0,k=0;
	int iBtd=g_iButtonsCount;
	BOOL bDeleted=FALSE;
	char szMEntry[256]={'\0'};
	TCHAR strbuf[256];
	HTREEITEM hti=NULL;
	TVITEM tvi;
	g_iButtonsCount=TreeView_GetCount(hButtonsList);
	tvi.pszText = strbuf;
	tvi.cchTextMax = 256;
	tvi.mask=TVIF_HANDLE|TVIF_TEXT ;
	tvi.hItem=TreeView_GetRoot(hButtonsList);
	
	TreeView_GetItem(hButtonsList,&tvi);
	li_ZeroQuickList(QuickList);
	BalanceButtons(iBtd,g_iButtonsCount);
	while(ButtonsList[iBl])
		{
		SortedList * sl=NULL;
		ListData* ld=ButtonsList[iBl];
		if (!ld->sl) break;
		sl=ld->sl;
		if(ld->dwOPFlags&QMF_DELETNEEDED)
			{
			bDeleted=(ld->dwOPFlags&QMF_NEW)?FALSE:TRUE;
			if(bDeleted) CleanSettings(ld->dwPos,-1);
			DestroyButton(iBl);
			continue;
			}
		if(ld->ptszQValue!=ld->ptszOPQValue)	
			{
 			if(ld->ptszQValue)
 				mir_free(ld->ptszQValue);
			ld->ptszQValue=(ld->ptszOPQValue)?ld->ptszOPQValue:NULL;
			}
		if(ld->ptszButtonName)
   				mir_free(ld->ptszButtonName);
  		if(iBl>0)
 			if(hti=TreeView_GetNextSibling(hButtonsList,hti?hti:tvi.hItem))
				{
				tvi.hItem=hti;
				TreeView_GetItem(hButtonsList,&tvi);
				}
 		ld->ptszButtonName=mir_tstrdup(tvi.pszText);
 	
		if(ld->ptszQValue)
			{
			mir_snprintf(szMEntry,255,"ButtonValue_%u",iBl);
			DBWriteContactSettingTString(NULL, PLGNAME,szMEntry,ld->ptszQValue);
			}
		if (ServiceExists(MS_BB_MODIFYBUTTON)&&((ld->dwOPFlags&QMF_NEW)||(ld->dwOPFlags&QMF_RENAMED)||bDeleted))
			{
			BBButton bb={0};
			bb.cbSize=sizeof(BBButton);
			bb.pszModuleName=PLGNAME;
			bb.dwButtonID=iBl;
			bb.ptszTooltip=ld->ptszButtonName;
			CallService(MS_BB_MODIFYBUTTON,0,(LPARAM)&bb);
			}	
		
		
		mir_snprintf(szMEntry,255,"ButtonName_%u",iBl);
		DBWriteContactSettingTString(NULL, PLGNAME,szMEntry,ld->ptszButtonName);
		ld->dwOPFlags=0;
		ld->dwPos=iBl;
		ld->bIsServName=ld->bIsOpServName;
		mir_snprintf(szMEntry,255,"RCEntryIsServiceName_%u",iBl);
		DBWriteContactSettingByte(NULL, PLGNAME,szMEntry,ld->bIsServName);
	
		bDeleted=FALSE;
		qsort(sl->items,sl->realCount,sizeof(ButtonData *),sstSortButtons); 
		for ( i=0; i < sl->realCount; i++ ) {
			ButtonData * bd= (ButtonData *)sl->items[i];
			if(bd->dwOPFlags&QMF_DELETNEEDED){
				RemoveMenuEntryNode(sl, i--);
				continue;
				}
			bd->bIsServName=bd->bIsOpServName;
			bd->bInQMenu=bd->bOpInQMenu;
			bd->dwPos=bd->dwOPPos;
			bd->fEntryType=bd->fEntryOpType;
			bd->dwOPFlags=0;
			if(bd->pszName!=bd->pszOpName)
				{
				if(bd->pszName)
					mir_free(bd->pszName);
				bd->pszName=bd->pszOpName?bd->pszOpName:NULL;
				}
			if(bd->pszValue!=bd->pszOpValue)
				{
				if(bd->pszValue)
					mir_free(bd->pszValue);
				bd->pszValue=bd->pszOpValue?bd->pszOpValue:NULL;
				}
			if(bd->bInQMenu)
				{
				QuickData* qd = (QuickData *)mir_alloc(sizeof(QuickData));
				qd->dwPos=k++;
				qd->fEntryType=bd->fEntryType;
				qd->bIsService=bd->bIsServName;
				qd->ptszValue=bd->pszValue;
				qd->ptszValueName=bd->pszName;
				List_InsertPtr(QuickList,qd);
				}
			SaveModuleSettings(iBl,bd);
			}
		CleanSettings(iBl,sl->realCount);
		iBl++;
		}
	
	DBWriteContactSettingByte(NULL, PLGNAME,"ButtonsCount", (BYTE)g_iButtonsCount);
	}
void RestoreModuleData(HWND hdlg)
	{
	int iBl=0,i=0;
	char szMEntry[256]={'\0'};
	while(ButtonsList[iBl])
		{
		SortedList * sl=NULL;
		ListData* ld=ButtonsList[iBl];
		if (!(sl=ld->sl)) break;
		if(ld->dwOPFlags&QMF_NEW)
			{
			DestroyButton(iBl);
			continue;
			}
		if(ld->ptszQValue!=ld->ptszOPQValue)	
			{
			if(ld->ptszOPQValue)
				mir_free(ld->ptszOPQValue);
			ld->ptszOPQValue=(ld->ptszQValue)?ld->ptszQValue:NULL;
			}
		ld->bIsOpServName=ld->bIsServName;
		ld->dwOPFlags=0;
		qsort(sl->items,sl->realCount,sizeof(ButtonData *),sstSortButtons); 
		for ( i=0; i < sl->realCount; i++ ) {
			ButtonData * bd= (ButtonData *)sl->items[i];
			if(bd->dwOPFlags&QMF_NEW){
				RemoveMenuEntryNode(sl, i--);
				continue;
				}
			bd->bIsOpServName=bd->bIsServName;
			bd->bOpInQMenu=bd->bInQMenu;
			bd->dwOPPos=bd->dwPos;
			bd->fEntryOpType=bd->fEntryType;
			bd->dwOPFlags=0;
			if(bd->pszName!=bd->pszOpName)
				{
				if(bd->pszOpName)
					mir_free(bd->pszOpName);
				bd->pszOpName=bd->pszName?bd->pszName:NULL;
				}
			if(bd->pszValue!=bd->pszOpValue)
				{
				if(bd->pszOpValue)
					mir_free(bd->pszOpValue);
				bd->pszOpValue=bd->pszValue?bd->pszValue:NULL;
				}
			}
		iBl++;
		}
	}
static int BuildMenuTree(HWND hToolBarTree,SortedList * sl)
	{
	TVINSERTSTRUCT tvis;
	int i;
	HTREEITEM hParent=NULL;
	tvis.hParent = NULL;
	tvis.hInsertAfter = TVI_LAST;
	tvis.item.mask = TVIF_PARAM | TVIF_TEXT;
	TreeView_DeleteAllItems( hToolBarTree );
	if (!sl) return 1;
	qsort(sl->items,sl->realCount,sizeof(ButtonData *),sstOpSortButtons); 
	for ( i=0; i < sl->realCount; i++ ) {
		ButtonData * bd= (ButtonData *)sl->items[i];
		if(bd->dwOPFlags&QMF_DELETNEEDED)
			continue;
		tvis.item.lParam= (LPARAM) bd;
		tvis.item.pszText= bd->pszOpName;
		if(bd->fEntryOpType==0)
			tvis.hParent = NULL;
		hParent=TreeView_InsertItem( hToolBarTree, &tvis );
		if(tvis.hParent) TreeView_Expand( hMenuTree, tvis.hParent, TVE_EXPAND );
		if (!bd->pszOpValue&&bd->fEntryOpType==0)
			{
			tvis.hParent = hParent;
			}
// 		else if (!(bd->fEntryOpType&QMF_EX_CHILD))
// 			tvis.hParent = NULL;
		}
	return 1;
	}
static int BuildButtonsList(HWND hToolBarTree)
	{
	TVINSERTSTRUCT tvis;
	int i=0;
	tvis.hParent = NULL;
	tvis.hInsertAfter = TVI_LAST;
	tvis.item.mask =TVIF_PARAM | TVIF_TEXT;
	TreeView_DeleteAllItems( hToolBarTree );
	
	//for(i=0;iptszButtonName;
		TreeView_InsertItem( hToolBarTree, &tvis );
		i++;
		}
	return 1;
	}
///////////////////////////////////
//From UserInfoEx by DeathAxe
//
void MoveItem( HTREEITEM hItem, HTREEITEM hInsertAfter, BOOLEAN bAsChild )
	{
	TVINSERTSTRUCT tvis;
	//TCHAR strbuf[128];
	HTREEITEM hParent, hChild, hNewItem;
	if ( !hItem || !hInsertAfter )
		return;
	if ( hItem == hInsertAfter )
		return;
	switch( ( ULONG_PTR )hInsertAfter ) {
		case TVI_ROOT:
		case TVI_FIRST:
		case TVI_LAST:
			hParent = NULL;
			bAsChild = FALSE;
			break;
		default:
			hParent = TreeView_GetParent( hMenuTree, hInsertAfter );
			break;
		}
	// do not move a parent next to its own children!
	if ( hItem == hParent )
		return;
	// prepare the insert structure
		{
		TCHAR strbuf[128];
		tvis.item.mask=TVIF_HANDLE|TVIF_PARAM|TVIF_TEXT;
		tvis.item.pszText=strbuf;
		tvis.item.cchTextMax=sizeof(strbuf);
		tvis.item.hItem=hItem;
		TreeView_GetItem(hMenuTree,&tvis.item);				
		}
		// item should be inserted as the first child of an existing root item
		if ( bAsChild ) { 
			tvis.hParent = hInsertAfter;
			tvis.hInsertAfter =   ( bAsChild == 2 ) ? TVI_LAST : TVI_FIRST ;
			}
		// item should be inserted after an existing item
		else {
			tvis.hParent = hParent;
			tvis.hInsertAfter = hInsertAfter;
			}
		// insert the item
		if ( !( hNewItem = TreeView_InsertItem( hMenuTree, &tvis )) )
			return;
		// move children
		hInsertAfter = hNewItem;
		while( hChild = TreeView_GetChild( hMenuTree, hItem )) {
			MoveItem( hChild, hInsertAfter, 2 );
			}
		// delete old tree
		TreeView_DeleteItem( hMenuTree, hItem );
		TreeView_SelectItem( hMenuTree, hNewItem );
		//TreeView_Expand( hMenuTree, hNewItem, TVE_EXPAND );
	}
///////
INT_PTR CALLBACK OptionsProc(HWND hdlg,UINT msg,WPARAM wparam,LPARAM lparam)
	{	
	switch(msg){
		case WM_INITDIALOG:{
			DWORD style;
			g_opHdlg=hdlg;
			bOptionsInit=TRUE;
			TranslateDialogDefault(hdlg); 
			if(g_iButtonsCount!=DBGetContactSettingByte(NULL, PLGNAME,"ButtonsCount", 0))
				{
				LOGFONT logFont;
				HFONT hFont;
				bNeedRestart=TRUE;
				EnableWindow(GetDlgItem(hdlg,IDC_BUTTONSLIST),FALSE);
				EnableWindow(GetDlgItem(hdlg,IDC_BLISTADD),FALSE);
				EnableWindow(GetDlgItem(hdlg,IDC_BLISTREMOVE),FALSE);
				EnableWindow(GetDlgItem(hdlg,IDC_MENUTREE),FALSE);
				EnableWindow(GetDlgItem(hdlg,IDC_MTREEADD),FALSE);
				EnableWindow(GetDlgItem(hdlg,IDC_MTREEREMOVE),FALSE);
				EnableWindow(GetDlgItem(hdlg,IDC_MENUVALUE),FALSE);
				EnableWindow(GetDlgItem(hdlg,IDC_RCLICKVALUE),FALSE);
				EnableWindow(GetDlgItem(hdlg,IDC_BUTTONNAME),FALSE);
				EnableWindow(GetDlgItem(hdlg,IDC_INQMENU),FALSE);
				EnableWindow(GetDlgItem(hdlg,IDC_ISSERVNAME),FALSE);
				EnableWindow(GetDlgItem(hdlg,IDC_MENUNAME),FALSE);	
				ShowWindow(GetDlgItem(hdlg,IDC_WARNING),SW_SHOW);
				hFont = (HFONT)SendMessage(GetDlgItem(hdlg, IDC_WARNING), WM_GETFONT, 0, 0);
				GetObject(hFont, sizeof logFont, &logFont);
				logFont.lfWeight = FW_BOLD;
				hFont = CreateFontIndirect(&logFont);
				SendMessage(GetDlgItem(hdlg, IDC_WARNING), WM_SETFONT, (WPARAM)hFont, 0);
				break;
				}
			
			g_iOPButtonsCount=g_iButtonsCount;
			hButtonsList=GetDlgItem(hdlg,IDC_BUTTONSLIST);
			hMenuTree=GetDlgItem(hdlg,IDC_MENUTREE);
			style = GetWindowLongPtr(hButtonsList,GWL_STYLE);
			style |=TVS_NOHSCROLL;
			SetWindowLongPtr(hButtonsList,GWL_STYLE, style);
			style = GetWindowLongPtr(hMenuTree,GWL_STYLE);
			style |=TVS_NOHSCROLL;			
			SetWindowLongPtr(hMenuTree,GWL_STYLE, style);
			BuildButtonsList(hButtonsList);
			
			if (!TreeView_GetCount(hButtonsList)) EnableWindow(GetDlgItem(hdlg,IDC_RCLICKVALUE),FALSE);
			oldBNameProc = (WNDPROC) SetWindowLongPtr(GetDlgItem(hdlg,IDC_BUTTONNAME), GWLP_WNDPROC, (LONG) EditSubclassProc);
			oldMNameProc = (WNDPROC) SetWindowLongPtr(GetDlgItem(hdlg,IDC_MENUNAME)  , GWLP_WNDPROC, (LONG) EditSubclassProc);
			
			EnableWindow(GetDlgItem(hdlg,IDC_MENUVALUE),FALSE);
			EnableWindow(GetDlgItem(hdlg,IDC_INQMENU),FALSE);
			EnableWindow(GetDlgItem(hdlg,IDC_ISSERVNAME),FALSE);
			CheckDlgButton(hdlg,IDC_RAUTOSEND,(g_bRClickAuto=DBGetContactSettingByte(NULL,PLGNAME,"RClickAuto",0)));
			CheckDlgButton(hdlg,IDC_LAUTOSEND,(g_bLClickAuto=DBGetContactSettingByte(NULL,PLGNAME,"LClickAuto",0)));
			CheckDlgButton(hdlg,IDC_ENABLEQUICKMENU,(g_bQuickMenu=DBGetContactSettingByte(NULL, PLGNAME,"QuickMenu", 1)));
		
			bOptionsInit=FALSE;
			}break;
		case WM_LBUTTONUP:
			if(drag) {
				TVHITTESTINFO hti; 
				HTREEITEM htiAfter=NULL;
				ButtonData* bd=NULL;
				TVITEM tvi;
				RECT rc;
				BYTE height;
				BOOLEAN bAsChild = FALSE;
				TreeView_SetInsertMark(hMenuTree, NULL, 0 );
				ReleaseCapture();
				SetCursor( LoadCursor( NULL, IDC_ARROW ));
				hti.pt.x = ( SHORT )LOWORD( lparam );
				hti.pt.y = ( SHORT )HIWORD( lparam );
				ClientToScreen(hdlg,&hti.pt);
				ScreenToClient(hMenuTree,&hti.pt);
				TreeView_HitTest( hMenuTree, &hti );
				if(TreeView_GetParent(hMenuTree,hti.hItem)&&TreeView_GetChild(hMenuTree,hDragItem))
					break;
				if(TreeView_GetChild(hMenuTree,hti.hItem)&&TreeView_GetChild(hMenuTree,hDragItem))
					break;
					if ( hti.flags & TVHT_ABOVE ) {
						htiAfter = TVI_FIRST;
						}
					else
						if ( hti.flags & ( TVHT_NOWHERE|TVHT_BELOW )) {
							htiAfter = TVI_LAST;
							}
						else
							if ( hti.flags & ( TVHT_ONITEM|TVHT_ONITEMRIGHT )) {
								// check where over the item, the pointer is
								if ( !TreeView_GetItemRect( hMenuTree, hti.hItem, &rc, FALSE )) {
									drag=0;
									break;
									}
								height = ( BYTE )( rc.bottom - rc.top );
								if ( hti.pt.y - ( height / 3 ) < rc.top ) {
									HTREEITEM hItem = hti.hItem;
									if ( !( hti.hItem = TreeView_GetPrevSibling( hMenuTree, hItem )) ) {
										if ( !( hti.hItem = TreeView_GetParent(hMenuTree, hItem )))
											htiAfter = TVI_FIRST;
										else
											bAsChild = TRUE;
										}
									}
								else 
									if ( hti.pt.y + ( height / 3 ) <= rc.bottom ) {
										bAsChild = TRUE;
										}
								}	
							if(TreeView_GetChild(hMenuTree,hDragItem)&&bAsChild)
								break;
							if(hti.hItem){
 									tvi.hItem=hti.hItem;
 									tvi.mask=TVIF_PARAM |TVIF_HANDLE;
 									TreeView_GetItem(hMenuTree,&tvi);
									if ((bd=(ButtonData*)tvi.lParam)&&(bd->fEntryOpType&QMF_EX_SEPARATOR))
										bAsChild = FALSE;
							 }
							if(TreeView_GetParent(hMenuTree,hti.hItem))
 								bAsChild = FALSE;
							MoveItem( hDragItem, htiAfter?htiAfter:hti.hItem, bAsChild );
							SendMessage(GetParent(hdlg),PSM_CHANGED,0,0);
							drag=0;
				}
			break; 
		///////////////////////////////////
		//From UserInfoEx by DeathAxe
		//
		case WM_MOUSEMOVE:
			{
			if (!drag) break;
				{
				TVHITTESTINFO hti;
				hti.pt.x=(short)LOWORD(lparam);
				hti.pt.y=(short)HIWORD(lparam);
				ClientToScreen(hdlg,&hti.pt);
				ScreenToClient(hMenuTree,&hti.pt);
				TreeView_HitTest(hMenuTree,&hti);
				if ( hti.flags & ( TVHT_ONITEM|TVHT_ONITEMRIGHT )) {
					RECT rc;
					BYTE height;
					if ( TreeView_GetItemRect(hMenuTree, hti.hItem, &rc, FALSE )) {
						height = ( BYTE )( rc.bottom - rc.top );
						if ( hti.pt.y - ( height / 3 ) < rc.top ) {
							SetCursor( LoadCursor( NULL, IDC_ARROW ));
							TreeView_SetInsertMark( hMenuTree, hti.hItem, 0 );
							}
						else
							if ( hti.pt.y + ( height / 3 ) > rc.bottom ) {
								SetCursor( LoadCursor( NULL, IDC_ARROW ));
								TreeView_SetInsertMark( hMenuTree, hti.hItem, 1 );
								}
							else {
								TreeView_SetInsertMark( hMenuTree, NULL, 0 );
								SetCursor( LoadCursor( GetModuleHandle(NULL), MAKEINTRESOURCE( 183 )) );
								}
						}
					}
				else {
					if ( hti.flags & TVHT_ABOVE ) SendMessage( hMenuTree, WM_VSCROLL, MAKEWPARAM( SB_LINEUP, 0 ), 0 );
					if ( hti.flags & TVHT_BELOW ) SendMessage( hMenuTree, WM_VSCROLL, MAKEWPARAM( SB_LINEDOWN, 0 ), 0 );
					TreeView_SetInsertMark( hMenuTree, NULL, 0 );
					}
				}
			}break;
			/////////////
		case WM_DESTROY:
			if (g_varhelpDlg)
				DestroyWindow(g_varhelpDlg);
			g_varhelpDlg=NULL;
			break;
		case WM_NOTIFY:{
			switch(((LPNMHDR)lparam)->idFrom)	{
		case 0:{
			if (((LPNMHDR)lparam)->code == PSN_APPLY ) {
				if (!bNeedRestart){
				SetMenuEntryProperties(hdlg);
				SaveMenuTree(hdlg); 
				}
				DBWriteContactSettingByte(NULL,PLGNAME,"RClickAuto",(BYTE)(g_bRClickAuto=IsDlgButtonChecked(hdlg,IDC_RAUTOSEND)));
				DBWriteContactSettingByte(NULL,PLGNAME,"LClickAuto",(BYTE)(g_bLClickAuto=IsDlgButtonChecked(hdlg,IDC_LAUTOSEND)));
				DBWriteContactSettingByte(NULL,PLGNAME,"QuickMenu",(BYTE)(g_bQuickMenu=IsDlgButtonChecked(hdlg,IDC_ENABLEQUICKMENU)));
				return 1;
				}
			else if (((LPNMHDR)lparam)->code == PSN_RESET ) {
					if (!bNeedRestart)
						RestoreModuleData(hdlg);
				return 1;
				}
			}
			break; 
		case IDC_MENUTREE:
			switch (((LPNMHDR)lparam)->code){
		case TVN_KEYDOWN:{
			TV_KEYDOWN* pTVKeyDown = (TV_KEYDOWN*) ((LPNMHDR)lparam);
			if ( pTVKeyDown->wVKey == VK_F2 )
				TreeView_EditLabel(hMenuTree,TreeView_GetSelection(hMenuTree));
			else if ( pTVKeyDown->wVKey == VK_DELETE )
					SendMessage(hdlg,WM_COMMAND,IDC_MTREEREMOVE,0);
			}break;
		case TVN_BEGINLABELEDITA:
		case TVN_BEGINLABELEDITW:
			hwndEdit=TreeView_GetEditControl(hMenuTree);
			oldEditProc = (WNDPROC) SetWindowLongPtr(hwndEdit, GWLP_WNDPROC, (LONG) LabelEditSubclassProc);
			break;
		case TVN_ENDLABELEDITA:
		case TVN_ENDLABELEDITW:
			{
			TVITEM tvi;
			ButtonData* bd=NULL;
			TCHAR strbuf[256];
			TCHAR szLabel[256];
			SetWindowLongPtr(hwndEdit, GWLP_WNDPROC, (LONG) oldEditProc);
			tvi.pszText = strbuf;
			tvi.cchTextMax = sizeof(strbuf);
			tvi.mask=TVIF_TEXT |TVIF_HANDLE|TVIF_PARAM;
			tvi.hItem=TreeView_GetSelection(hMenuTree);
			TreeView_GetItem(hMenuTree,&tvi);
			GetWindowText(hwndEdit, szLabel, sizeof(szLabel));
			hwndEdit=NULL;
			if (!_tcslen(szLabel)) break;
			if (bd = (ButtonData*)tvi.lParam){
				if (!_tcscmp(szLabel,_T("---"))) {
					if(TreeView_GetChild(hMenuTree,tvi.hItem))
						break;
					else{
						bd->fEntryOpType=QMF_EX_SEPARATOR;
						EnableWindow(GetDlgItem(hdlg,IDC_MENUVALUE),FALSE);
						EnableWindow(GetDlgItem(hdlg,IDC_ISSERVNAME),FALSE);
						SetWindowText(GetDlgItem(hdlg,IDC_MENUVALUE),_T(""));
						}
					}
				else {
					bd->fEntryOpType&=~QMF_EX_SEPARATOR;
						EnableWindow(GetDlgItem(hdlg,IDC_MENUVALUE),TRUE);
						EnableWindow(GetDlgItem(hdlg,IDC_ISSERVNAME),TRUE);
						SetWindowText(GetDlgItem(hdlg,IDC_MENUVALUE),bd->pszOpValue/*?bd->pszOpValue:bd->pszValue*/);
					}
				bd->pszOpName=mir_tstrdup(szLabel);
				
				tvi.pszText=szLabel;
				TreeView_SetItem(hMenuTree, &tvi);
				SendMessage(GetParent(hdlg),PSM_CHANGED,0,0);
				}
			}break;
		case NM_KILLFOCUS:
			TreeView_EndEditLabelNow(hButtonsList, 1);
			break;
		case TVN_BEGINDRAGA:
		case TVN_BEGINDRAGW:
			SetCapture(hdlg);
			drag=1;
			hDragItem=((LPNMTREEVIEW)lparam)->itemNew.hItem;
			TreeView_SelectItem(hMenuTree,hDragItem);
			break;
		case TVN_SELCHANGINGA:
		case TVN_SELCHANGINGW:
			{
			TVITEM tvi;
			HTREEITEM hti;
			ButtonData* bd;
			hti=TreeView_GetSelection(hMenuTree);
			if (hti==NULL)
				break;
			tvi.hItem=hti;
			tvi.mask=TVIF_HANDLE|TVIF_PARAM;
			TreeView_GetItem(hMenuTree,&tvi);
			if (tvi.lParam == 0)
				break;
			bd = ( ButtonData* )tvi.lParam;
			if (bd) {
				TCHAR szValue[256];
				GetWindowText(GetDlgItem(hdlg,IDC_MENUVALUE), szValue, sizeof(szValue));
				if(_tcslen(szValue))
					{
					if(bd->pszOpValue&&(bd->pszOpValue!=bd->pszValue))
						mir_free(bd->pszOpValue);
					bd->pszOpValue=mir_tstrdup(szValue);
					}
				bd->bOpInQMenu=IsDlgButtonChecked(hdlg,IDC_INQMENU);
				bd->bIsOpServName=IsDlgButtonChecked(hdlg,IDC_ISSERVNAME);
				}
			}break;
		case TVN_SELCHANGEDA:
		case TVN_SELCHANGEDW:
			{
			TVITEM tvi;
			HTREEITEM hti;
			ButtonData* bd=NULL;
			hti=TreeView_GetSelection(hMenuTree);
			if (hti==NULL)
				break;
			tvi.mask=TVIF_HANDLE|TVIF_PARAM;
			tvi.hItem=hti;
			TreeView_GetItem(hMenuTree,&tvi);
			bd = ( ButtonData* )tvi.lParam;
			if (bd) {
				if (!TreeView_GetChild(hMenuTree, tvi.hItem)&&!(bd->fEntryOpType&QMF_EX_SEPARATOR))
					{
					EnableWindow(GetDlgItem(hdlg,IDC_MENUVALUE),TRUE);
					EnableWindow(GetDlgItem(hdlg,IDC_ISSERVNAME),TRUE);
					EnableWindow(GetDlgItem(hdlg,IDC_INQMENU),TRUE);
					SetWindowText(GetDlgItem(hdlg,IDC_MENUVALUE),bd->pszOpValue/*?bd->pszOpValue:bd->pszValue*/);
					}
				else
					{
					EnableWindow(GetDlgItem(hdlg,IDC_MENUVALUE),FALSE);
					EnableWindow(GetDlgItem(hdlg,IDC_ISSERVNAME),FALSE);
					if (!(bd->fEntryOpType&QMF_EX_SEPARATOR))
						EnableWindow(GetDlgItem(hdlg,IDC_INQMENU),FALSE);
					SetWindowText(GetDlgItem(hdlg,IDC_MENUVALUE),_T(""));
					}
				CheckDlgButton(hdlg,IDC_INQMENU,bd->bOpInQMenu);
				CheckDlgButton(hdlg,IDC_ISSERVNAME,bd->bIsOpServName);
				}
			}
		}break;
		case IDC_BUTTONSLIST:
			switch (((LPNMHDR)lparam)->code) {
		case TVN_KEYDOWN:{
			TV_KEYDOWN* pTVKeyDown = (TV_KEYDOWN*) ((LPNMHDR)lparam);
			if ( pTVKeyDown->wVKey == VK_F2 )
				TreeView_EditLabel(hButtonsList,TreeView_GetSelection(hButtonsList));
			else if ( pTVKeyDown->wVKey == VK_DELETE )
				SendMessage(hdlg,WM_COMMAND,IDC_BLISTREMOVE,0);
			}break;
		case TVN_BEGINLABELEDITA:
		case TVN_BEGINLABELEDITW:
			hwndEdit=TreeView_GetEditControl(hButtonsList);
			oldEditProc = (WNDPROC) SetWindowLongPtr(hwndEdit, GWLP_WNDPROC, (LONG) LabelEditSubclassProc);
			break;
		case TVN_ENDLABELEDITA:
		case TVN_ENDLABELEDITW:{
			TVITEM tvi;
			TCHAR strbuf[128];
			TCHAR szLabel[128];
			SetWindowLongPtr(hwndEdit, GWLP_WNDPROC, (LONG) oldEditProc);
			tvi.pszText = strbuf;
			tvi.cchTextMax = sizeof(strbuf);
			tvi.mask=TVIF_TEXT |TVIF_HANDLE|TVIF_PARAM;
			tvi.hItem=TreeView_GetSelection(hButtonsList);
			TreeView_GetItem(hButtonsList,&tvi);
			GetWindowText(hwndEdit, szLabel, sizeof(szLabel));
			hwndEdit=NULL;
			if (!_tcslen(szLabel)) break;
			tvi.pszText=szLabel;
			((ListData*)tvi.lParam)->dwOPFlags|=QMF_RENAMED;	
			TreeView_SetItem(hButtonsList, &tvi);
			SendMessage(GetParent(hdlg),PSM_CHANGED,0,0);
			}break;
		case TVN_SELCHANGINGA:
		case TVN_SELCHANGINGW:
			SetMenuEntryProperties(hdlg);
			break;
		case TVN_SELCHANGEDA:
		case TVN_SELCHANGEDW:{
			TVITEM tvi;
			HTREEITEM hti;
			hti=TreeView_GetSelection(hButtonsList);
			if(hti==NULL||!TreeView_GetCount(hButtonsList)) {
				EnableWindow(GetDlgItem(hdlg,IDC_MENUVALUE),FALSE);
				EnableWindow(GetDlgItem(hdlg,IDC_ISSERVNAME),FALSE);
				EnableWindow(GetDlgItem(hdlg,IDC_INQMENU),FALSE);
				EnableWindow(GetDlgItem(hdlg,IDC_ISSERVNAME2),FALSE);
				SetWindowText(GetDlgItem(hdlg,IDC_MENUVALUE),_T(""));
				break;
				}
			
			tvi.mask=TVIF_HANDLE|TVIF_PARAM;
			tvi.hItem=hti;
			TreeView_GetItem(hButtonsList,&tvi);
			if(tvi.lParam==0) break;
			BuildMenuTree(hMenuTree,(SortedList *)((ListData*)tvi.lParam)->sl);
			SetWindowText(GetDlgItem(hdlg,IDC_MENUVALUE),_T(""));
			EnableWindow(GetDlgItem(hdlg,IDC_RCLICKVALUE),TRUE);
			EnableWindow(GetDlgItem(hdlg,IDC_ISSERVNAME2),TRUE);
			CheckDlgButton(hdlg,IDC_ISSERVNAME2,((ListData*)tvi.lParam)->bIsOpServName);
			if (((ListData*)tvi.lParam)->ptszOPQValue) 
				SetWindowText(GetDlgItem(hdlg,IDC_RCLICKVALUE),((ListData*)tvi.lParam)->ptszOPQValue);
			else
				SetWindowText(GetDlgItem(hdlg,IDC_RCLICKVALUE),_T(""));
			}break;
				}break;
				}
			}break;
		case WM_COMMAND:{
		switch(LOWORD(wparam)) {
		case IDC_VARHELP:{
			if (!g_varhelpDlg)
				g_varhelpDlg=CreateDialog(hinstance,MAKEINTRESOURCE(IDD_HELPDIALOG), 0, HelpDlgProc);
			else
				//ShowWindow(g_varhelpDlg,SW_SHOWDEFAULT);
				SetWindowPos(g_varhelpDlg,0,0,0,0,0,SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE);
			}break;
		case IDC_BLISTADD:{
			TVINSERTSTRUCT tvis;
			ListData* ld=NULL;
			TCHAR namebuff[MAX_PATH]={'\0'};
			int count=TreeView_GetCount(hButtonsList);
			if (count>10) break;
			if(g_iOPButtonsCount==99){
				MessageBox(NULL, TranslateT("Congratulation!\r\nYou have clicked this button 100 times!\r\nThere was access violation at this point...\r\nAnd now function for freeing resources must be called...\r\nBut no! there's only break :D"), TranslateT("You win!"),MB_OK);
				break;
				}
			ld = (ListData *)mir_alloc(sizeof(ListData));
			ButtonsList[g_iOPButtonsCount++]=ld;
			ld->sl=List_Create(0,1);
			ld->dwOPFlags=QMF_NEW;
			ld->bIsOpServName=0;
			ld->ptszButtonName=NULL;
			ld->ptszOPQValue=NULL;
			ld->ptszQValue=NULL;
			tvis.hParent = NULL;
			tvis.hInsertAfter = TVI_LAST;
			
			GetWindowText(GetDlgItem(hdlg,IDC_BUTTONNAME),namebuff,MAX_PATH);
			tvis.item.mask=TVIF_PARAM|TVIF_TEXT;
			tvis.item.pszText=(_tcslen(namebuff))?namebuff:TranslateT("New Button");
			tvis.item.lParam=(LPARAM)ld;
			TreeView_SelectItem(hButtonsList,TreeView_InsertItem(hButtonsList,&tvis));
			}break;
		case IDC_BLISTREMOVE:{ 
			TVITEM tvi;
			ListData* ld;
			if (!(tvi.hItem=TreeView_GetSelection(hButtonsList)))
				break;
			tvi.mask=TVIF_HANDLE|TVIF_PARAM;
			TreeView_GetItem(hButtonsList,&tvi);
			ld= (ListData*)tvi.lParam;
			ld->dwOPFlags|=QMF_DELETNEEDED;	
			TreeView_DeleteItem(hButtonsList,tvi.hItem);
			if (!TreeView_GetCount(hButtonsList))
				{
				TreeView_DeleteAllItems(hMenuTree);
				EnableWindow(GetDlgItem(hdlg,IDC_MENUVALUE),FALSE);
				EnableWindow(GetDlgItem(hdlg,IDC_RCLICKVALUE),FALSE);
				EnableWindow(GetDlgItem(hdlg,IDC_ISSERVNAME),FALSE);
				EnableWindow(GetDlgItem(hdlg,IDC_INQMENU),FALSE);
				EnableWindow(GetDlgItem(hdlg,IDC_ISSERVNAME2),FALSE);
				SetWindowText(GetDlgItem(hdlg,IDC_MENUVALUE),_T(""));
				SetWindowText(GetDlgItem(hdlg,IDC_RCLICKVALUE),_T(""));
				}
			}break;
		case IDC_MTREEADD:{ 
			TVINSERTSTRUCT tvis;
			TVITEM tvi;
			ButtonData *bd=NULL;
			SortedList *sl=NULL;
			TCHAR namebuff[MAX_PATH]={'\0'};
			
			if (!TreeView_GetCount(hButtonsList)) break;
			if (!(tvi.hItem=TreeView_GetSelection(hButtonsList))) break;
			
			bd = (ButtonData *)mir_alloc(sizeof(ButtonData));
			memset(bd,0,sizeof(ButtonData));
			GetWindowText(GetDlgItem(hdlg,IDC_MENUNAME),namebuff,MAX_PATH);
			bd->dwOPPos=TreeView_GetCount(hMenuTree)-1;
			bd->pszOpName=_tcslen(namebuff)?mir_tstrdup(namebuff):mir_tstrdup(TranslateT("New Menu Entry"));
			bd->pszOpValue=mir_tstrdup(bd->pszOpName);
			bd->fEntryOpType=!_tcscmp(namebuff,_T("---"))?QMF_EX_SEPARATOR:0;
			bd->dwOPFlags=QMF_NEW;
			bd->pszName=NULL;
			bd->pszValue=NULL;
			tvi.mask=TVIF_HANDLE|TVIF_PARAM;
			
			TreeView_GetItem(hButtonsList,&tvi);
			sl=((ListData*)tvi.lParam)->sl;
			List_InsertPtr(sl,bd);
			tvis.hParent = NULL;
			tvis.hInsertAfter = TVI_LAST;
			tvis.item.mask=TVIF_PARAM|TVIF_TEXT;
			tvis.item.pszText=bd->pszOpName;
			tvis.item.lParam=(LPARAM)bd;
			TreeView_SelectItem(hMenuTree,TreeView_InsertItem(hMenuTree,&tvis));
			}break;
		case IDC_MTREEREMOVE:{
			TVITEM tvi;
			TVINSERTSTRUCT tvis;
			HTREEITEM hti=NULL;
			ButtonData *bd=NULL;
			tvi.mask=TVIF_HANDLE|TVIF_PARAM;
			if (!(tvi.hItem=TreeView_GetSelection(hMenuTree)))
				break;
			TreeView_GetItem(hMenuTree,&tvi);
			hti=tvi.hItem;
			bd= (ButtonData*)tvi.lParam;
			bd->dwOPFlags|=QMF_DELETNEEDED;			
			if(tvi.hItem=TreeView_GetChild(hMenuTree,tvi.hItem)) {
				TCHAR strbuf[128];
				while(tvi.hItem){
					tvis.hInsertAfter=hti;
					tvi.pszText = strbuf;
					tvi.cchTextMax = sizeof(strbuf);
					tvi.mask=TVIF_HANDLE|TVIF_PARAM|TVIF_TEXT;
					TreeView_GetItem(hMenuTree,&tvi); 
					tvis.hParent=NULL;
					tvis.item=tvi;
					TreeView_InsertItem(hMenuTree,&tvis);
					tvi.hItem=TreeView_GetNextSibling(hMenuTree,tvi.hItem);
					}
				}
			TreeView_DeleteItem(hMenuTree,hti);
			if (!TreeView_GetCount(hMenuTree)) {
				EnableWindow(GetDlgItem(hdlg,IDC_MENUVALUE),FALSE);
				EnableWindow(GetDlgItem(hdlg,IDC_ISSERVNAME),FALSE);
				EnableWindow(GetDlgItem(hdlg,IDC_INQMENU),FALSE);
				SetWindowText(GetDlgItem(hdlg,IDC_MENUVALUE),_T(""));
				}
			}break;
				}
			}break;
		case WM_NCDESTROY: 
			if(oldBNameProc) SetWindowLongPtr(GetDlgItem(hdlg,IDC_BUTTONNAME), GWLP_WNDPROC, (LONG) oldBNameProc);
			if(oldMNameProc) SetWindowLongPtr(GetDlgItem(hdlg,IDC_MENUNAME)  , GWLP_WNDPROC, (LONG) oldMNameProc);
			break; 
		case WM_CLOSE:
			EndDialog(hdlg,0);
			return 0;
		}
		if (HIWORD(wparam)==BN_CLICKED && GetFocus()==(HWND)lparam)
			SendMessage(GetParent(hdlg),PSM_CHANGED,0,0);
		else if ((HIWORD(wparam) == EN_CHANGE)&&(GetFocus()==(HWND)lparam))
			if (!bOptionsInit)	SendMessage(GetParent(hdlg),PSM_CHANGED,0,0);
	return 0;
	}
int OptionsInit(WPARAM wparam,LPARAM lparam)
{
	OPTIONSDIALOGPAGE odp={0};
	odp.cbSize = sizeof(odp);
	odp.position = 940000000;
	odp.hInstance = hinstance;
	odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS);
	odp.pszTitle = LPGEN("Quick Messages");
	odp.pfnDlgProc = OptionsProc;
	odp.pszGroup = LPGEN("Message Sessions");
	odp.flags = ODPF_BOLDGROUPS;
	Options_AddPage(wparam,&odp);
	return 0;
}