/*
	
	Cool Scrollbar Library Version 1.2
 
	Module: coolsblib.c
	Copyright (c) J Brown 2001
 
	This code is freeware, however, you may not publish
	this code elsewhere or charge any money for it. This code
	is supplied as-is. I make no guarantees about the suitability
	of this code - use at your own risk.
	
	It would be nice if you credited me, in the event
	that you use this code in a product.
 
	VERSION HISTORY:
 
	 V1.2: TreeView problem fixed by Diego Tartara
		   Small problem in thumbsize calculation also fixed (thanks Diego!)
 
	 V1.1: Added support for Right-left windows
	       Changed calling convention of APIs to WINAPI (__stdcall)
		   Completely standalone (no need for c-runtime)
 
	 V1.0: Apr 2001: Initial Version
 
*/
 
#define STRICT
 
#include <windows.h>
#include <commctrl.h>
#include <tchar.h>
#include "coolscroll.h"
#include "userdefs.h"
#include "coolsb_internal.h"
 
static TCHAR szPropStr[] = _T("CoolSBSubclassPtr");
 
LRESULT CALLBACK CoolSBWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
 
SCROLLWND *GetScrollWndFromHwnd(HWND hwnd)
{
	return (SCROLLWND *)GetProp(hwnd, szPropStr);
}
 
SCROLLBAR *GetScrollBarFromHwnd(HWND hwnd, UINT nBar)
{
	SCROLLWND *sw = GetScrollWndFromHwnd(hwnd);
	
	if(!sw) return 0;
	
	if(nBar == SB_HORZ)
		return &sw->sbarHorz;
	else if(nBar == SB_VERT)
		return &sw->sbarVert;
	else
		return 0;
}
 
BOOL WINAPI CoolSB_IsCoolScrollEnabled(HWND hwnd)
{
	if(GetScrollWndFromHwnd(hwnd))
		return TRUE;
	else
		return FALSE;
}
 
BOOL GetScrollRect(SCROLLWND *sw, UINT nBar, HWND hwnd, RECT *rect);
 
//
//	Special support for USER32.DLL patching (using Detours library)
//	The only place we call a real scrollbar API is in InitializeCoolSB,
//	where we call EnableScrollbar.
//	
//	We HAVE to call the origial EnableScrollbar function, 
//	so we need to be able to set a pointer to this func when using
//	using Detours (or any other LIB??)
//
 
static BOOL (WINAPI * pEnableScrollBar) (HWND, UINT, UINT) = 0;
 
void WINAPI CoolSB_SetESBProc(void *proc)
{
	pEnableScrollBar = proc;
}
//
//
 
static void RedrawNonClient(HWND hwnd, BOOL fFrameChanged)
{
	if(fFrameChanged == FALSE)
	{
		/*
		RECT rect;
		HRGN hrgn1, hrgn2;
		
		SCROLLWND *sw = GetScrollWndFromHwnd(hwnd);
		
		GetScrollRect(sw, SB_HORZ, hwnd, &rect);
		hrgn1 = CreateRectRgnIndirect(&rect);
		
		GetScrollRect(sw, SB_VERT, hwnd, &rect);
		hrgn2 = CreateRectRgnIndirect(&rect);
		
		CombineRgn(hrgn1, hrgn2, hrgn1, RGN_OR);
		
		SendMessage(hwnd, WM_NCPAINT, (WPARAM)hrgn1, 0);
		
		DeleteObject(hrgn1);
		DeleteObject(hrgn2);*/
 
		SendMessage(hwnd, WM_NCPAINT, (WPARAM)1, 0);
	}
	else
	{
		SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE
			| SWP_FRAMECHANGED | SWP_DRAWFRAME);
	}
}
 
//
//	return the default minimum size of a scrollbar thumb
//
int WINAPI CoolSB_GetDefaultMinThumbSize(void)
{
	DWORD dwVersion = GetVersion();
 
	// set the minimum thumb size for a scrollbar. This
	// differs between NT4 and 2000, so need to check to see
	// which platform we are running under
	if(dwVersion < 0x80000000)              // Windows NT/2000
	{
		if(LOBYTE(LOWORD(dwVersion)) >= 5)
			return MINTHUMBSIZE_2000;
		else
			return MINTHUMBSIZE_NT4;
	}
	else
	{
		return MINTHUMBSIZE_NT4;
	}
}
 
static SCROLLINFO *GetScrollInfoFromHwnd(HWND hwnd, int fnBar)
{
	SCROLLBAR *sb = GetScrollBarFromHwnd(hwnd, fnBar);
 
	if(sb == 0)
		return FALSE;
 
	if(fnBar == SB_HORZ)
	{
		return &sb->scrollInfo;
	}
	else if(fnBar == SB_VERT)
	{
		return &sb->scrollInfo;
	}
	else
		return NULL;
}
//
//	Initialize the cool scrollbars for a window by subclassing it
//	and using the coolsb window procedure instead
//
BOOL WINAPI InitializeCoolSB(HWND hwnd, ptr_themeRGB ThemeRGB)
{
	SCROLLWND *sw;
	SCROLLINFO *si;
	INITCOMMONCONTROLSEX ice;
	TOOLINFO ti;
	RECT rect;
	DWORD dwCurStyle;
	//BOOL fDisabled;
 
	if(pEnableScrollBar == 0)
		pEnableScrollBar = EnableScrollBar;
 
	GetClientRect(hwnd, &rect);
 
	//if we have already initialized Cool Scrollbars for this window,
	//then stop the user from doing it again
	if(GetScrollWndFromHwnd(hwnd) != 0)
	{
		return FALSE;
	}
 
	fThemeRGB = ThemeRGB;
 
	//allocate a private scrollbar structure which we 
	//will use to keep track of the scrollbar data
	sw = (SCROLLWND *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SCROLLWND));
 
	si = &sw->sbarHorz.scrollInfo;
	si->cbSize = sizeof(SCROLLINFO);
	si->fMask  = SIF_ALL;
	GetScrollInfo(hwnd, SB_HORZ, si);
 
	si = &sw->sbarVert.scrollInfo;
	si->cbSize = sizeof(SCROLLINFO);
	si->fMask  = SIF_ALL;
	GetScrollInfo(hwnd, SB_VERT, si);
 
	//check to see if the window has left-aligned scrollbars
	if(GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_LEFTSCROLLBAR)
		sw->fLeftScrollbar = TRUE;
	else
		sw->fLeftScrollbar = FALSE;
 
	dwCurStyle = GetWindowLong(hwnd, GWL_STYLE);
 
	SetProp(hwnd, szPropStr, (HANDLE)sw);
 
	//try to enable the scrollbar arrows - if the return value is
	//non-zero, then the scrollbars were previously disabled
	//fDisabled = pEnableScrollBar(hwnd, SB_HORZ, ESB_ENABLE_BOTH);
 
	//scrollbars will automatically get enabled, even if
	//they aren't to start with....sorry, but there isn't an
	//easy alternative.
	if(dwCurStyle & WS_HSCROLL)
		sw->sbarHorz.fScrollFlags = CSBS_VISIBLE;
 
	if(dwCurStyle & WS_VSCROLL)
		sw->sbarVert.fScrollFlags = CSBS_VISIBLE;
 
	//need to be able to distinguish between horizontal and vertical
	//scrollbars in some instances
	sw->sbarHorz.nBarType	     = SB_HORZ;
	sw->sbarVert.nBarType	     = SB_VERT;
 
	sw->sbarHorz.fFlatScrollbar  = CSBS_NORMAL;
	sw->sbarVert.fFlatScrollbar  = CSBS_NORMAL;
 
	//set the default arrow sizes for the scrollbars
	sw->sbarHorz.nArrowLength	 = SYSTEM_METRIC;
	sw->sbarHorz.nArrowWidth	 = SYSTEM_METRIC;
	sw->sbarVert.nArrowLength	 = SYSTEM_METRIC;
	sw->sbarVert.nArrowWidth	 = SYSTEM_METRIC;
 
	sw->bPreventStyleChange		 = FALSE;
	
	sw->oldproc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)CoolSBWndProc);
 
	CoolSB_SetMinThumbSize(hwnd, SB_BOTH, CoolSB_GetDefaultMinThumbSize());
 
#ifdef COOLSB_TOOLTIPS
	ice.dwSize = sizeof(ice);
	ice.dwICC  = ICC_BAR_CLASSES;
	InitCommonControlsEx(&ice);
 
	sw->hwndToolTip = CreateWindowEx(WS_EX_TOPMOST | WS_EX_TOOLWINDOW, TOOLTIPS_CLASS, _T(""),
                            WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
                            CW_USEDEFAULT, CW_USEDEFAULT,
                            CW_USEDEFAULT, CW_USEDEFAULT,
                            hwnd, NULL, GetModuleHandle(0),
                            NULL);
 
	ti.cbSize = sizeof(TOOLINFO);
	ti.uFlags = TTF_IDISHWND;
	ti.hwnd   = hwnd;
	ti.uId    = (UINT)hwnd;
	ti.lpszText = LPSTR_TEXTCALLBACK;
	ti.hinst   = GetModuleHandle(0);
 
	SendMessage(sw->hwndToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti);
	
#else
 
	UNREFERENCED_PARAMETER(ice);
	UNREFERENCED_PARAMETER(ti);
	sw->hwndToolTip = 0;
 
#endif
	
	//send the window a frame changed message to update the scrollbars
	RedrawNonClient(hwnd, TRUE);
 
	return TRUE;
}
 
BOOL WINAPI CoolSB_EnableScrollBar	(HWND hwnd, int wSBflags, UINT wArrows)
{
	SCROLLBAR *sbar;
	UINT oldstate;
	BOOL bFailed = FALSE;
 
	if(!CoolSB_IsCoolScrollEnabled(hwnd))
		return EnableScrollBar(hwnd, wSBflags, wArrows);
 
	if((wSBflags == SB_HORZ || wSBflags == SB_BOTH) && 
		(sbar = GetScrollBarFromHwnd(hwnd, SB_HORZ)))
	{
		oldstate = sbar->fScrollFlags;
		
		//clear any existing state, and OR in the disabled flags
		sbar->fScrollFlags = (sbar->fScrollFlags & ~ESB_DISABLE_BOTH) | wArrows;
 
		if(oldstate == sbar->fScrollFlags)
			bFailed = TRUE;
 
	}
 
	if((wSBflags == SB_VERT || wSBflags == SB_BOTH) && 
		(sbar = GetScrollBarFromHwnd(hwnd, SB_VERT)))
	{
		oldstate = sbar->fScrollFlags;
		
		//clear any existing state, and OR in the disabled flags
		sbar->fScrollFlags = (sbar->fScrollFlags & ~ESB_DISABLE_BOTH) | wArrows;
 
		if(oldstate == sbar->fScrollFlags)
			bFailed = TRUE;
	}
 
	return !bFailed;
}
 
BOOL WINAPI CoolSB_GetScrollBarInfo(HWND hwnd)
{
//	SCROLLBARINFO sbi; not defined in winuser.h
	return FALSE;	
}
 
BOOL WINAPI CoolSB_GetScrollInfo (HWND hwnd, int fnBar, LPSCROLLINFO lpsi)
{
	SCROLLINFO *mysi;
	BOOL copied = FALSE;
	
	if(!lpsi)
		return FALSE;
 
	if(!(mysi = GetScrollInfoFromHwnd(hwnd, fnBar)))
	{
		return GetScrollInfo(hwnd, fnBar, lpsi);
	}
	
	if(lpsi->fMask & SIF_PAGE)
	{
		lpsi->nPage = mysi->nPage;
		copied = TRUE;
	}
 
	if(lpsi->fMask & SIF_POS)
	{
		lpsi->nPos = mysi->nPos;
		copied = TRUE;
	}
 
	if(lpsi->fMask & SIF_TRACKPOS)
	{
		lpsi->nTrackPos = mysi->nTrackPos;
		copied = TRUE;
	}
 
	if(lpsi->fMask & SIF_RANGE)
	{
		lpsi->nMin = mysi->nMin;
		lpsi->nMax = mysi->nMax;
		copied = TRUE;
	}
 
	return copied;
}
 
int	WINAPI CoolSB_GetScrollPos (HWND hwnd, int nBar)
{
	SCROLLINFO *mysi;
	
	if(!(mysi = GetScrollInfoFromHwnd(hwnd, nBar)))
		return GetScrollPos(hwnd, nBar);
 
	return mysi->nPos;
}
 
BOOL WINAPI CoolSB_GetScrollRange (HWND hwnd, int nBar, LPINT lpMinPos, LPINT lpMaxPos)
{
	SCROLLINFO *mysi;
	
	if(!lpMinPos || !lpMaxPos)
		return FALSE;
 
	if(!(mysi = GetScrollInfoFromHwnd(hwnd, nBar)))
		return GetScrollRange(hwnd, nBar, lpMinPos, lpMaxPos);
 
	*lpMinPos = mysi->nMin;
	*lpMaxPos = mysi->nMax;
 
	return TRUE;
}
 
int	WINAPI CoolSB_SetScrollInfo (HWND hwnd, int fnBar, LPSCROLLINFO lpsi, BOOL fRedraw)
{
	SCROLLINFO *mysi;
	SCROLLBAR *sbar;
	BOOL       fRecalcFrame = FALSE;
 
	if(!lpsi)
		return FALSE;
 
	if(!(mysi = GetScrollInfoFromHwnd(hwnd, fnBar)))
		return SetScrollInfo(hwnd, fnBar, lpsi, fRedraw);
 
	//if(CoolSB_IsThumbTracking(hwnd))
	//	return mysi->nPos;
 
	if(lpsi->fMask & SIF_RANGE)
	{
		mysi->nMin = lpsi->nMin;
		mysi->nMax = lpsi->nMax;
	}
 
	//The nPage member must specify a value from 0 to nMax - nMin +1. 
	if(lpsi->fMask & SIF_PAGE)
	{
		UINT t = (UINT)(mysi->nMax - mysi->nMin + 1);
		mysi->nPage = min(max(0, lpsi->nPage), t);
	}
 
	//The nPos member must specify a value between nMin and nMax - max(nPage - 1, 0).
	if(lpsi->fMask & SIF_POS)
	{
		mysi->nPos = max(lpsi->nPos, mysi->nMin);
		mysi->nPos = min((UINT)mysi->nPos, mysi->nMax - max(mysi->nPage - 1, 0));
	}
 
	sbar = GetScrollBarFromHwnd(hwnd, fnBar);
 
	if((lpsi->fMask & SIF_DISABLENOSCROLL) || (sbar->fScrollFlags & CSBS_THUMBALWAYS))
	{
		if(!sbar->fScrollVisible)
		{
			CoolSB_ShowScrollBar(hwnd, fnBar, TRUE);
			fRecalcFrame = TRUE;
		}
	}
	else
	{
		if(    mysi->nPage >  (UINT)mysi->nMax 
			|| mysi->nPage == (UINT)mysi->nMax && mysi->nMax == 0
			|| mysi->nMax  <= mysi->nMin)
		{
			if(sbar->fScrollVisible)
			{
				CoolSB_ShowScrollBar(hwnd, fnBar, FALSE);
				fRecalcFrame = TRUE;
			}
		}
		else
		{
			if(!sbar->fScrollVisible)
			{
				CoolSB_ShowScrollBar(hwnd, fnBar, TRUE);
				fRecalcFrame = TRUE;
			}
 
		}
 
	}
 
	if(fRedraw && !CoolSB_IsThumbTracking(hwnd))
		RedrawNonClient(hwnd, fRecalcFrame);
	
	return mysi->nPos;
}
 
 
int WINAPI CoolSB_SetScrollPos(HWND hwnd, int nBar, int nPos, BOOL fRedraw)
{
	SCROLLINFO *mysi;
	int oldpos;
	
	if(!(mysi = GetScrollInfoFromHwnd(hwnd, nBar)))
	{
		return SetScrollPos(hwnd, nBar, nPos, fRedraw);
	}
 
	//this is what should happen, but real scrollbars don't work like this..
	//if(CoolSB_IsThumbTracking(hwnd))
	//	return mysi->nPos;
 
	//validate and set the scollbar position
	oldpos = mysi->nPos;
	mysi->nPos = max(nPos, mysi->nMin);
	mysi->nPos = min((UINT)mysi->nPos, mysi->nMax - max(mysi->nPage - 1, 0));
 
	if(fRedraw && !CoolSB_IsThumbTracking(hwnd))
		RedrawNonClient(hwnd, FALSE);
 
	return oldpos;
}
 
int WINAPI CoolSB_SetScrollRange (HWND hwnd, int nBar, int nMinPos, int nMaxPos, BOOL fRedraw)
{
	SCROLLINFO *mysi;
	
	if(!(mysi = GetScrollInfoFromHwnd(hwnd, nBar)))
		return SetScrollRange(hwnd, nBar, nMinPos, nMaxPos, fRedraw);
 
	if(CoolSB_IsThumbTracking(hwnd))
		return mysi->nPos;
 
	//hide the scrollbar if nMin == nMax
	//nMax-nMin must not be greater than MAXLONG
	mysi->nMin = nMinPos;
	mysi->nMax = nMaxPos;
	
	if(fRedraw)
		RedrawNonClient(hwnd, FALSE);
 
	return TRUE;
}
 
//
//	Show or hide the specified scrollbars
//
BOOL WINAPI CoolSB_ShowScrollBar (HWND hwnd, int wBar, BOOL fShow)
{
	SCROLLBAR *sbar;
	BOOL bFailed = FALSE;
	DWORD dwStyle = GetWindowLong(hwnd, GWL_STYLE);
 
	if(!CoolSB_IsCoolScrollEnabled(hwnd))
		return ShowScrollBar(hwnd, wBar, fShow);
 
	if((wBar == SB_HORZ || wBar == SB_BOTH) && 
	   (sbar = GetScrollBarFromHwnd(hwnd, SB_HORZ)))
	{
		sbar->fScrollFlags  =  sbar->fScrollFlags & ~CSBS_VISIBLE;
		sbar->fScrollFlags |= (fShow == TRUE ? CSBS_VISIBLE : 0);
		//bFailed = TRUE;
 
		if(fShow)	SetWindowLong(hwnd, GWL_STYLE, dwStyle | WS_HSCROLL);
		else		SetWindowLong(hwnd, GWL_STYLE, dwStyle & ~WS_HSCROLL);
	}
 
	if((wBar == SB_VERT || wBar == SB_BOTH) && 
	   (sbar = GetScrollBarFromHwnd(hwnd, SB_VERT)))
	{
		sbar->fScrollFlags  =  sbar->fScrollFlags & ~CSBS_VISIBLE;
		sbar->fScrollFlags |= (fShow == TRUE ? CSBS_VISIBLE : 0);
		//bFailed = TRUE;
 
		if(fShow)	SetWindowLong(hwnd, GWL_STYLE, dwStyle | WS_VSCROLL);
		else		SetWindowLong(hwnd, GWL_STYLE, dwStyle & ~WS_VSCROLL);
	}
 
	if(bFailed)
	{
		return FALSE;
	}
	else
	{
		//DWORD style = GetWindowLong(hwnd, GWL_STYLE);
		//style |= WS_VSCROLL;
		
		//if(s
		//SetWindowLong(hwnd, GWL_STYLE, style);
 
		SetWindowPos(hwnd, 0, 0, 0, 0, 0, 
			SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | 
			SWP_NOACTIVATE | SWP_FRAMECHANGED);
		
		return TRUE;
	}
}
 
//
//	Remove cool scrollbars from the specified window.
//
HRESULT WINAPI UninitializeCoolSB(HWND hwnd)
{
	int i = 0;
	SCROLLWND *sw = GetScrollWndFromHwnd(hwnd);
	if(!sw) return E_FAIL;
 
	//restore the window procedure with the original one
	SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)sw->oldproc);
 
	RemoveProp(hwnd, szPropStr);
	//SetWindowLong(hwnd, GWL_USERDATA, 0);
 
	//finally, release the memory needed for the cool scrollbars
	HeapFree(GetProcessHeap(), 0, sw);
 
    //Force WM_NCCALCSIZE and WM_NCPAINT so the original scrollbars can kick in
    RedrawNonClient(hwnd, TRUE);
 
	fThemeRGB = NULL;
 
	return S_OK;
}
 
#ifdef INCLUDE_BUTTONS
 
//
//	Cool scrollbar specific interface (BUTTON support)
//
 
//
//	Insert a button into the scrollbar area
//
//	wSBflags - SB_HORZ / SB_VERT only
//	uPos     - position into which to insert.
//				can be 0 to insert at the start, or -1 to insert
//				at the end of previously inserted buttons
//
 
BOOL WINAPI CoolSB_InsertButton(HWND hwnd, int wSBflags, UINT nPos, SCROLLBUT *psb)
{
	SCROLLBAR *sbar;
	SCROLLBUT *sbut;
	UINT i;
 
	if(!psb) return FALSE;
 
	if(!(sbar = GetScrollBarFromHwnd(hwnd, wSBflags)))
		return FALSE;
	
	//check that we havn't reached the maximum allowed buttons yet
	if(sbar->nButtons == MAX_COOLSB_BUTS)
		return FALSE;
 
	//insert at end
	if(nPos == -1)
	{
		sbut = &sbar->sbButtons[sbar->nButtons];
	}
	//otherwise, need to make room
	else if((int)nPos < 0 || (int)nPos > (UINT)sbar->nButtons)
	{
		return FALSE;
	}
	else
	{
		//insert space for the button at the specified position
		for(i = sbar->nButtons; i > nPos; i--)
		{
			sbar->sbButtons[i] = sbar->sbButtons[i-1];
		}
 
		sbut = &sbar->sbButtons[nPos];
	}
 
	//only set the button's properties if they are
	//specified by the SCROLLBUT->fMask. 
	//Otherwise, use a default property value
 
	if(psb->fMask & SBBF_TYPE)
		sbut->uButType   = psb->uButType;
	else
		sbut->uButType	 = SBBT_PUSHBUTTON;
 
	if(psb->fMask & SBBF_STATE)
		sbut->uState	 = psb->uState;
	else
		sbut->uState	 = 0;
 
	if(psb->fMask & SBBF_ID)
		sbut->uCmdId     = psb->uCmdId;
	else
		sbut->uCmdId	 = 0;
 
	if(psb->fMask & SBBF_SIZE)
		sbut->nSize		 = psb->nSize;
	else
		sbut->nSize		 = -1;
 
	if(psb->fMask & SBBF_PLACEMENT)
		sbut->uPlacement = psb->uPlacement;
	else
		sbut->uPlacement = SBBP_LEFT;
 
	if(psb->fMask & SBBF_BITMAP)
		sbut->hBmp		 = psb->hBmp;
	else
		sbut->hBmp		 = 0;
 
	if(psb->fMask & SBBF_ENHMETAFILE)
		sbut->hEmf		 = psb->hEmf;
	else
		sbut->hEmf		 = 0;
 
	if(psb->fMask & SBBF_CURSOR)
		sbut->hCurs = psb->hCurs;
	else
		sbut->hCurs = 0;
 
	/*
		We don't use the callback function anymore. The uButType
		member must now specify SBBT_OWNERDRAW, and a WM_NOTIFY will
		be sent when a button must be drawn
	if((psb->fMask & SBBF_OWNERDRAW) && ((psb->uButType & SBBT_MASK) == SBBT_OWNERDRAW))
		pDrawProc	 = psb->pDrawProc;
	else
		pDrawProc	 = 0;*/
 
	sbar->nButtons++;
	sbut->nSizeReserved = sbut->nSize;
 
	//MAKE SURE that any resizable buttons are only to the left / above
	//a scrollbar. We don't support resize operations to the right of a scrollbar
	if((sbut->uButType & SBBM_RESIZABLE) &&	sbut->uPlacement == SBBP_RIGHT)
		sbut->uButType &= ~SBBM_RESIZABLE;
 
	if(psb->fMask & SBBF_BUTMINMAX)
	{
		sbut->nMinSize = psb->nMinSize;
		sbut->nMaxSize = psb->nMaxSize;
	}
	else
	{
		sbut->nMinSize = 0;
		sbut->nMaxSize = -1;
	}
 
	return TRUE;
}
 
static SCROLLBUT *GetButtonFromId(SCROLLBAR *sbar, UINT uCmdId)
{
	int i;
	for(i = 0; i < sbar->nButtons; i++)
	{
		if(sbar->sbButtons[i].uCmdId == uCmdId)
			return &sbar->sbButtons[i];
	}
 
	return 0;
}
 
//
//	Modify the properties of the specified scrollbar button.
//	wSBflags - SB_HORZ / SB_VERT only
//	uItem    - the command identifier specified when the button was created,
//			   or a non-negative position of the button, depending on if
//			   fByCmd is FALSE or TRUE, respectively
//
BOOL WINAPI CoolSB_ModifyButton (HWND hwnd, int wSBflags, UINT uItem, BOOL fByCmd, SCROLLBUT *psb)
{
	SCROLLBAR *sbar;
	SCROLLBUT *sbut;
 
	if(!psb) return FALSE;
 
	//find if this window is CoolScroll enabled
	if(!(sbar = GetScrollBarFromHwnd(hwnd, wSBflags)))
		return FALSE;
 
	//find the button to modify, depending on if we
	//are modifying by position or command id
	if(fByCmd == FALSE)
	{
		//button from position
		if((int)uItem < 0 || (int)uItem >= (UINT)sbar->nButtons)
			return FALSE;
		else
			sbut = &sbar->sbButtons[uItem];
	}
	else if(fByCmd == TRUE)
	{
		//button from command identifier
		if(!(sbut = GetButtonFromId(sbar, uItem)))
			return FALSE;
	}
 
	if(psb->fMask & SBBF_TYPE)			sbut->uButType   = psb->uButType;
	if(psb->fMask & SBBF_STATE)			sbut->uState	 = psb->uState;
	if(psb->fMask & SBBF_ID)			sbut->uCmdId     = psb->uCmdId;
	if(psb->fMask & SBBF_SIZE)			sbut->nSize		 = psb->nSize;
	if(psb->fMask & SBBF_PLACEMENT)		sbut->uPlacement = psb->uPlacement;
	if(psb->fMask & SBBF_BITMAP)		sbut->hBmp		 = psb->hBmp;
	if(psb->fMask & SBBF_ENHMETAFILE)	sbut->hEmf		 = psb->hEmf;
	if(psb->fMask & SBBF_CURSOR)		sbut->hCurs		 = psb->hCurs;
	
	if(psb->fMask & SBBF_BUTMINMAX)
	{
		sbut->nMinSize = psb->nMinSize;
		sbut->nMaxSize = psb->nMaxSize;
	}
 
	return TRUE;
}
 
BOOL WINAPI CoolSB_RemoveButton(HWND hwnd, int wSBflags, UINT uItem, BOOL fByCmd)
{
	int i;
	SCROLLBAR *sbar;
 
	//find if this window is CoolScroll enabled
	if(!(sbar = GetScrollBarFromHwnd(hwnd, wSBflags)))
		return FALSE;
 
	//find the button to modify, depending on if we
	//are modifying by position or command id
	if(fByCmd == FALSE && ((int)uItem < 0 || (int)uItem >= (UINT)sbar->nButtons))
	{
		return FALSE;
	}
	else if(fByCmd == TRUE)
	{
		//find the button with the specified command id
		for(i = 0; i < sbar->nButtons; i++)
		{
			if(sbar->sbButtons[i].uCmdId == uItem)
			{
				//change the id to an index
				uItem = i;
				break;
			}
		}
 
		//if we failed to find the button...
		if(i == sbar->nButtons) return FALSE;
	}
 
	//remove the button!
	for(i = uItem; i < sbar->nButtons - 1; i++)
	{
		sbar->sbButtons[i] = sbar->sbButtons[i+1];
	}
 
	sbar->nButtons--;
	
	RedrawNonClient(hwnd, TRUE);
 
	return TRUE;
}
 
//
//	fill in the supplied SCROLLBUT structure
//
BOOL WINAPI CoolSB_GetButton(HWND hwnd, int wSBflags, UINT uItem, BOOL fByCmd, SCROLLBUT *psb)
{
	SCROLLBAR *sbar;
	SCROLLBUT *sbut;
 
	if(!psb) return FALSE;
 
	//find if this window is CoolScroll enabled
	if(!(sbar = GetScrollBarFromHwnd(hwnd, wSBflags)))
		return FALSE;
 
	//find the button to modify, depending on if we
	//are modifying by position or command id
	if(fByCmd == FALSE)
	{
		//button from position
		if((int)uItem < 0 || (int)uItem >= (UINT)sbar->nButtons)
			return FALSE;
		else
			sbut = &sbar->sbButtons[uItem];
	}
	else if(fByCmd == TRUE)
	{
		//button from command identifier
		if(!(sbut = GetButtonFromId(sbar, uItem)))
			return FALSE;
	}
 
	//copy them across
	*psb = *sbut;
 
	return FALSE; 
}
 
#else
 
BOOL WINAPI CoolSB_InsertButton(HWND hwnd, int wSBflags, UINT nPos,  SCROLLBUT *psb)				{	return FALSE; }
BOOL WINAPI CoolSB_ModifyButton(HWND hwnd, int wSBflags, UINT uItem, BOOL fByCmd, SCROLLBUT *psb)	{	return FALSE; }
BOOL WINAPI CoolSB_RemoveButton(HWND hwnd, int wSBflags, UINT uItem, BOOL fByCmd)					{	return FALSE; }
BOOL WINAPI CoolSB_GetButton   (HWND hwnd, int wSBflags, UINT uItem, BOOL fByCmd, SCROLLBUT *psb)	{	return FALSE; }
 
#endif //INCLUDE_BUTTONS
 
//
//	Set the size of the scrollbars
//
BOOL WINAPI CoolSB_SetSize	(HWND hwnd, int wBar, int nLength, int nWidth)
{
	SCROLLBAR *sbar;
	
	if(nLength == 0 || nWidth == 0)
		return FALSE;
 
	if(nLength < -8 || nWidth < -8)
		return FALSE;
 
	if(nLength > 256 || nWidth > 256)
		return FALSE;
 
	if(!GetScrollWndFromHwnd(hwnd))
		return FALSE;
 
	int bRedraw = 0;
	if((wBar == SB_HORZ || wBar == SB_BOTH) && 
	   (sbar = GetScrollBarFromHwnd(hwnd, SB_HORZ)))
	{
		bRedraw = (sbar->nArrowLength != nLength) || (sbar->nArrowWidth != nWidth);
		sbar->nArrowLength = nLength;
		sbar->nArrowWidth  = nWidth;
	}
 
	if((wBar == SB_VERT || wBar == SB_BOTH) && 
	   (sbar = GetScrollBarFromHwnd(hwnd, SB_VERT)))
	{
		bRedraw = bRedraw || (sbar->nArrowLength != nLength) || (sbar->nArrowWidth != nWidth);
		sbar->nArrowLength = nLength;
		sbar->nArrowWidth  = nWidth;
	}
 
	if (bRedraw)
		RedrawNonClient(hwnd, TRUE);
 
	return TRUE;
}
 
 
//
//	Alter the display mode of the scrollbars
//	wBar   - SB_HORZ / SB_VERT / SB_BOTH
//	nStyle - CSBF_NORMAL / CSBF_FLAT / CSBF_HOTTRACKED
//
BOOL WINAPI CoolSB_SetStyle(HWND hwnd, int wBar, UINT nStyle)
{
	SCROLLBAR *sbar;
 
	if(!GetScrollWndFromHwnd(hwnd))
		return FALSE;
 
	int bRedraw = 0;
	if((wBar == SB_HORZ || wBar == SB_BOTH) && 
	   (sbar = GetScrollBarFromHwnd(hwnd, SB_HORZ)))
	{
		bRedraw = sbar->fFlatScrollbar != nStyle;
		sbar->fFlatScrollbar = nStyle;
	}
 
	if((wBar == SB_VERT || wBar == SB_BOTH) && 
	   (sbar = GetScrollBarFromHwnd(hwnd, SB_VERT)))
	{
		bRedraw = bRedraw || (sbar->fFlatScrollbar != nStyle);
		sbar->fFlatScrollbar = nStyle;
	}
 
	if (bRedraw)
		RedrawNonClient(hwnd, FALSE);
 
	return TRUE;
}
 
//
//	Set if the thumb is always visible, even if there is no data to
//  scroll. Setting this keeps the scrollbar enabled, but the thumb
//  covers the whole area
//	
BOOL WINAPI CoolSB_SetThumbAlways(HWND hwnd, int wBar, BOOL fThumbAlways)
{
	SCROLLBAR *sbar;
 
	if(!GetScrollWndFromHwnd(hwnd))
		return FALSE;
 
	if((wBar == SB_HORZ || wBar == SB_BOTH) && 
	   (sbar = GetScrollBarFromHwnd(hwnd, SB_HORZ)))
	{
		if(fThumbAlways)
			sbar->fScrollFlags |=  CSBS_THUMBALWAYS;
		else
			sbar->fScrollFlags &= ~CSBS_THUMBALWAYS;
	}
 
	if((wBar == SB_VERT || wBar == SB_BOTH) && 
	   (sbar = GetScrollBarFromHwnd(hwnd, SB_VERT)))
	{
		if(fThumbAlways)
			sbar->fScrollFlags |=  CSBS_THUMBALWAYS;
		else
			sbar->fScrollFlags &= ~CSBS_THUMBALWAYS;
	}
 
	RedrawNonClient(hwnd, FALSE);
 
	return TRUE;
}
 
//
//	Set the minimum size, in pixels, that the thumb box will shrink to.
//
BOOL WINAPI CoolSB_SetMinThumbSize(HWND hwnd, UINT wBar, UINT size)
{
	SCROLLBAR *sbar;
 
	if(!GetScrollWndFromHwnd(hwnd))
		return FALSE;
 
	if(size == -1)
		size = CoolSB_GetDefaultMinThumbSize();
 
	if((wBar == SB_HORZ || wBar == SB_BOTH) && 
	   (sbar = GetScrollBarFromHwnd(hwnd, SB_HORZ)))
	{
		sbar->nMinThumbSize = size;
	}
 
	if((wBar == SB_VERT || wBar == SB_BOTH) && 
	   (sbar = GetScrollBarFromHwnd(hwnd, SB_VERT)))
	{
		sbar->nMinThumbSize = size;
	}
 
	return TRUE;
}

V303 The function 'GetWindowLong' is deprecated in the Win64 system. It is safer to use the 'GetWindowLongPtr' function.

V303 The function 'GetWindowLong' is deprecated in the Win64 system. It is safer to use the 'GetWindowLongPtr' function.

V303 The function 'GetWindowLong' is deprecated in the Win64 system. It is safer to use the 'GetWindowLongPtr' function.

V303 The function 'SetWindowLong' is deprecated in the Win64 system. It is safer to use the 'SetWindowLongPtr' function.

V303 The function 'SetWindowLong' is deprecated in the Win64 system. It is safer to use the 'SetWindowLongPtr' function.

V303 The function 'SetWindowLong' is deprecated in the Win64 system. It is safer to use the 'SetWindowLongPtr' function.

V303 The function 'SetWindowLong' is deprecated in the Win64 system. It is safer to use the 'SetWindowLongPtr' function.

V547 Expression '(0) > (lpsi->nPage)' is always false. Unsigned type value is never < 0.

V547 Expression 'bFailed' is always false.

V555 The expression '(mysi->nPage - 1) > (0)' will work as 'mysi->nPage != 1'.

V555 The expression '(mysi->nPage - 1) > (0)' will work as 'mysi->nPage != 1'.

V522 There might be dereferencing of a potential null pointer 'sbar'.

V676 It is incorrect to compare the variable of BOOL type with TRUE. Correct expression is: 'fShow != FALSE'.

V676 It is incorrect to compare the variable of BOOL type with TRUE. Correct expression is: 'fShow != FALSE'.