From f920ef497f3299ae24fe783ce03bdd93b419f764 Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Fri, 18 May 2012 22:02:50 +0000 Subject: plugins folders renaming git-svn-id: http://svn.miranda-ng.org/main/trunk@60 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/Clist_nicer/coolsb/coolsb.dsp | 92 + plugins/Clist_nicer/coolsb/coolsb_internal.h | 95 + plugins/Clist_nicer/coolsb/coolsblib.cpp | 1003 ++++++++ plugins/Clist_nicer/coolsb/coolsblib.h | 41 + plugins/Clist_nicer/coolsb/coolscroll.cpp | 3206 ++++++++++++++++++++++++++ plugins/Clist_nicer/coolsb/coolscroll.h | 232 ++ plugins/Clist_nicer/coolsb/userdefs.h | 79 + 7 files changed, 4748 insertions(+) create mode 100644 plugins/Clist_nicer/coolsb/coolsb.dsp create mode 100644 plugins/Clist_nicer/coolsb/coolsb_internal.h create mode 100644 plugins/Clist_nicer/coolsb/coolsblib.cpp create mode 100644 plugins/Clist_nicer/coolsb/coolsblib.h create mode 100644 plugins/Clist_nicer/coolsb/coolscroll.cpp create mode 100644 plugins/Clist_nicer/coolsb/coolscroll.h create mode 100644 plugins/Clist_nicer/coolsb/userdefs.h (limited to 'plugins/Clist_nicer/coolsb') diff --git a/plugins/Clist_nicer/coolsb/coolsb.dsp b/plugins/Clist_nicer/coolsb/coolsb.dsp new file mode 100644 index 0000000000..34e7a537a1 --- /dev/null +++ b/plugins/Clist_nicer/coolsb/coolsb.dsp @@ -0,0 +1,92 @@ +# Microsoft Developer Studio Project File - Name="coolsb" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** NICHT BEARBEITEN ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=coolsb - Win32 Debug +!MESSAGE Dies ist kein gültiges Makefile. Zum Erstellen dieses Projekts mit NMAKE +!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und führen Sie den Befehl +!MESSAGE +!MESSAGE NMAKE /f "coolsb.mak". +!MESSAGE +!MESSAGE Sie können beim Ausführen von NMAKE eine Konfiguration angeben +!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel: +!MESSAGE +!MESSAGE NMAKE /f "coolsb.mak" CFG="coolsb - Win32 Debug" +!MESSAGE +!MESSAGE Für die Konfiguration stehen zur Auswahl: +!MESSAGE +!MESSAGE "coolsb - Win32 Release" (basierend auf "Win32 (x86) Static Library") +!MESSAGE "coolsb - Win32 Debug" (basierend auf "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "coolsb - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "coolsb - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "coolsb - Win32 Release" +# Name "coolsb - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# End Target +# End Project diff --git a/plugins/Clist_nicer/coolsb/coolsb_internal.h b/plugins/Clist_nicer/coolsb/coolsb_internal.h new file mode 100644 index 0000000000..8a394f8a51 --- /dev/null +++ b/plugins/Clist_nicer/coolsb/coolsb_internal.h @@ -0,0 +1,95 @@ +#ifndef _COOLSB_INTERNAL_INCLUDED +#define _COOLSB_INTERNAL_INCLUDED + +#ifdef __cplusplus +extern "C"{ +#endif + +#include + +// +// SCROLLBAR datatype. There are two of these structures per window +// +typedef struct +{ + UINT fScrollFlags; //flags + BOOL fScrollVisible; //if this scrollbar visible? + SCROLLINFO scrollInfo; //positional data (range, position, page size etc) + + int nArrowLength; //perpendicular size (height of a horizontal, width of a vertical) + int nArrowWidth; //parallel size (width of horz, height of vert) + + //data for inserted buttons + SCROLLBUT sbButtons[MAX_COOLSB_BUTS]; + int nButtons; + int nButSizeBefore; //size to the left / above the bar + int nButSizeAfter; //size to the right / below the bar + + BOOL fButVisibleBefore; //if the buttons to the left are visible + BOOL fButVisibleAfter; //if the buttons to the right are visible + + int nBarType; //SB_HORZ / SB_VERT + + UINT fFlatScrollbar; //do we display flat scrollbars? + int nMinThumbSize; + +} SCROLLBAR; + +// +// Container structure for a cool scrollbar window. +// +typedef struct +{ + UINT bars; //which of the scrollbars do we handle? SB_VERT / SB_HORZ / SB_BOTH + WNDPROC oldproc; //old window procedure to call for every message + + SCROLLBAR sbarHorz; //one scrollbar structure each for + SCROLLBAR sbarVert; //the horizontal and vertical scrollbars + + BOOL fThumbTracking; // are we currently thumb-tracking?? + BOOL fLeftScrollbar; // support the WS_EX_LEFTSCROLLBAR style + + HWND hwndToolTip; // tooltip support!!! + + //size of the window borders + int cxLeftEdge, cxRightEdge; + int cyTopEdge, cyBottomEdge; + + // To prevent calling original WindowProc in response + // to our own temporary style change (fixes TreeView problem) + BOOL bPreventStyleChange; + +} SCROLLWND; + + +// +// PRIVATE INTERNAL FUNCTIONS +// +SCROLLWND *GetScrollWndFromHwnd(HWND hwnd); +#define InvertCOLORREF(col) ((~col) & 0x00ffffff) + +#define COOLSB_TIMERID1 65533 //initial timer +#define COOLSB_TIMERID2 65534 //scroll message timer +#define COOLSB_TIMERID3 -14 //mouse hover timer +#define COOLSB_TIMERINTERVAL1 300 +#define COOLSB_TIMERINTERVAL2 55 +#define COOLSB_TIMERINTERVAL3 20 //mouse hover time + + +// +// direction: 0 - same axis as scrollbar (i.e. width of a horizontal bar) +// 1 - perpendicular dimesion (i.e. height of a horizontal bar) +// +#define SM_CXVERTSB 1 +#define SM_CYVERTSB 0 +#define SM_CXHORZSB 0 +#define SM_CYHORZSB 1 +#define SM_SCROLL_WIDTH 1 +#define SM_SCROLL_LENGTH 0 + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/plugins/Clist_nicer/coolsb/coolsblib.cpp b/plugins/Clist_nicer/coolsb/coolsblib.cpp new file mode 100644 index 0000000000..ac9ee2a360 --- /dev/null +++ b/plugins/Clist_nicer/coolsb/coolsblib.cpp @@ -0,0 +1,1003 @@ +/* + + 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 _WIN32_WINNT 0x0501 +#define _WIN32_IE 0x0501 + +#include +#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??) +// + +typedef BOOL (WINAPI *WPROC)(HWND, UINT, UINT); + +static WPROC pEnableScrollBar = 0; + +void WINAPI CoolSB_SetESBProc(WPROC 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) +{ + 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; + } + + //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); + //SetWindowLongPtr(hwnd, GWLP_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); + + 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; + + if((wBar == SB_HORZ || wBar == SB_BOTH) && + (sbar = GetScrollBarFromHwnd(hwnd, SB_HORZ))) + { + sbar->nArrowLength = nLength; + sbar->nArrowWidth = nWidth; + } + + if((wBar == SB_VERT || wBar == SB_BOTH) && + (sbar = GetScrollBarFromHwnd(hwnd, SB_VERT))) + { + sbar->nArrowLength = nLength; + sbar->nArrowWidth = nWidth; + } + + 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; + + if((wBar == SB_HORZ || wBar == SB_BOTH) && + (sbar = GetScrollBarFromHwnd(hwnd, SB_HORZ))) + { + sbar->fFlatScrollbar = nStyle; + } + + if((wBar == SB_VERT || wBar == SB_BOTH) && + (sbar = GetScrollBarFromHwnd(hwnd, SB_VERT))) + { + sbar->fFlatScrollbar = nStyle; + } + + 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; +} diff --git a/plugins/Clist_nicer/coolsb/coolsblib.h b/plugins/Clist_nicer/coolsb/coolsblib.h new file mode 100644 index 0000000000..d9b1c711f3 --- /dev/null +++ b/plugins/Clist_nicer/coolsb/coolsblib.h @@ -0,0 +1,41 @@ +#ifndef _SUPERSCROLL_INCLUDED +#define _SUPERSCROLL_INCLUDED + +#ifdef __cplusplus +extern "C"{ +#endif + +#include + + +#ifdef __cplusplus +} +#endif + +#endif + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/Clist_nicer/coolsb/coolscroll.cpp b/plugins/Clist_nicer/coolsb/coolscroll.cpp new file mode 100644 index 0000000000..68fd144edb --- /dev/null +++ b/plugins/Clist_nicer/coolsb/coolscroll.cpp @@ -0,0 +1,3206 @@ +/* + Cool Scrollbar Library Version 1.2 + + Module: coolscroll.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) + Now supports ALL windows with appropriate USER32.DLL patching + (you provide!!) + + V1.0: Apr 2001: Initial Version + + IMPORTANT: + This whole library is based around code for a horizontal scrollbar. + All "vertical" scrollbar drawing / mouse interaction uses the + horizontal scrollbar functions, but uses a trick to convert the vertical + scrollbar coordinates into horizontal equivelants. When I started this project, + I quickly realised that the code for horz/vert bars was IDENTICAL, apart + from the fact that horizontal code uses left/right coords, and vertical code + uses top/bottom coords. On entry to a "vertical" drawing function, for example, + the coordinates are "rotated" before the horizontal function is called, and + then rotated back once the function has completed. When something needs to + be drawn, the coords are converted back again before drawing. + + This trick greatly reduces the amount of code required, and makes + maintanence much simpler. This way, only one function is needed to draw + a scrollbar, but this can be used for both horizontal and vertical bars + with careful thought. +*/ + +#define _WIN32_WINNT 0x0501 +#define _WIN32_IE 0x0501 + +#include +#include "coolscroll.h" +#include "userdefs.h" +#include "coolsb_internal.h" + +//define some values if the new version of common controls +//is not available. +#ifndef NM_CUSTOMDRAW +#define NM_CUSTOMDRAW (NM_FIRST-12) +#define CDRF_DODEFAULT 0x0000 +#define CDRF_SKIPDEFAULT 0x0004 +#define CDDS_PREPAINT 0x0001 +#define CDDS_POSTPAINT 0x0002 +#endif + +// +// Special thumb-tracking variables +// +// +static UINT uCurrentScrollbar = COOLSB_NONE; //SB_HORZ / SB_VERT +static UINT uCurrentScrollPortion = HTSCROLL_NONE; +static UINT uCurrentButton = 0; + +static RECT rcThumbBounds; //area that the scroll thumb can travel in +static int nThumbSize; //(pixels) +static int nThumbPos; //(pixels) +static int nThumbMouseOffset; //(pixels) +static int nLastPos = -1; //(scrollbar units) +static int nThumbPos0; //(pixels) initial thumb position + +// +// Temporary state used to auto-generate timer messages +// +static UINT_PTR uMouseOverId = 0; +static UINT uMouseOverScrollbar = COOLSB_NONE; +static UINT uHitTestPortion = HTSCROLL_NONE; +static UINT uLastHitTestPortion = HTSCROLL_NONE; +static RECT MouseOverRect; + +static UINT uScrollTimerMsg = 0; +static UINT uScrollTimerPortion = HTSCROLL_NONE; +static UINT_PTR uScrollTimerId = 0; +static HWND hwndCurCoolSB = 0; + +extern int CustomDrawScrollBars(NMCSBCUSTOMDRAW *nmcsbcd); + +// +// Provide this so there are NO dependencies on CRT +// +static void CoolSB_ZeroMemory(void *ptr, DWORD bytes) +{ + BYTE *bptr = (BYTE *)ptr; + + while(bytes--) *bptr++ = 0; +} + +BOOL WINAPI CoolSB_IsThumbTracking(HWND hwnd) +{ + SCROLLWND *sw; + + if((sw = GetScrollWndFromHwnd(hwnd)) == NULL) + return FALSE; + else + return sw->fThumbTracking; +} + +// +// swap the rectangle's x coords with its y coords +// +static void __stdcall RotateRect(RECT *rect) +{ + int temp; + temp = rect->left; + rect->left = rect->top; + rect->top = temp; + + temp = rect->right; + rect->right = rect->bottom; + rect->bottom = temp; +} + +// +// swap the coords if the scrollbar is a SB_VERT +// +static void __stdcall RotateRect0(SCROLLBAR *sb, RECT *rect) +{ + if(sb->nBarType == SB_VERT) + RotateRect(rect); +} + +// +// Calculate if the SCROLLINFO members produce +// an enabled or disabled scrollbar +// +static BOOL IsScrollInfoActive(SCROLLINFO *si) +{ + if((si->nPage > (UINT)si->nMax + || si->nMax <= si->nMin || si->nMax == 0)) + return FALSE; + else + return TRUE; +} + +// +// Return if the specified scrollbar is enabled or not +// +static BOOL IsScrollbarActive(SCROLLBAR *sb) +{ + SCROLLINFO *si = &sb->scrollInfo; + if(((sb->fScrollFlags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH) || + !(sb->fScrollFlags & CSBS_THUMBALWAYS) && !IsScrollInfoActive(si)) + return FALSE; + else + return TRUE; +} + +// +// Draw a standard scrollbar arrow +// +static int DrawScrollArrow(SCROLLBAR *sbar, HDC hdc, RECT *rect, UINT arrow, BOOL fMouseDown, BOOL fMouseOver) +{ + UINT ret; + UINT flags = arrow; + + //HACKY bit so this routine can be called by vertical and horizontal code + if(sbar->nBarType == SB_VERT) + { + if(flags & DFCS_SCROLLLEFT) flags = flags & ~DFCS_SCROLLLEFT | DFCS_SCROLLUP; + if(flags & DFCS_SCROLLRIGHT) flags = flags & ~DFCS_SCROLLRIGHT | DFCS_SCROLLDOWN; + } + + if(fMouseDown) flags |= (DFCS_FLAT | DFCS_PUSHED); + +#ifdef FLAT_SCROLLBARS + if(sbar->fFlatScrollbar != CSBS_NORMAL) + { + HDC hdcmem1, hdcmem2; + HBITMAP hbm1, oldbm1; + HBITMAP hbm2, oldbm2; + RECT rc; + int width, height; + + rc = *rect; + width = rc.right-rc.left; + height = rc.bottom-rc.top; + SetRect(&rc, 0, 0, width, height); + + //MONOCHROME bitmap to convert the arrow to black/white mask + hdcmem1 = CreateCompatibleDC(hdc); + hbm1 = CreateBitmap(width, height, 1, 1, NULL); + UnrealizeObject(hbm1); + oldbm1 = reinterpret_cast(SelectObject(hdcmem1, hbm1)); + + + //NORMAL bitmap to draw the arrow into + hdcmem2 = CreateCompatibleDC(hdc); + hbm2 = CreateCompatibleBitmap(hdc, width, height); + UnrealizeObject(hbm2); + oldbm2 = reinterpret_cast(SelectObject(hdcmem2, hbm2)); + + + flags = flags & ~DFCS_PUSHED | DFCS_FLAT; //just in case + DrawFrameControl(hdcmem2, &rc, DFC_SCROLL, flags); + + +#ifndef HOT_TRACKING + if(fMouseDown) + { + //uncomment these to make the cool scrollbars + //look like the common controls flat scrollbars + //fMouseDown = FALSE; + //fMouseOver = TRUE; + } +#endif + //draw a flat monochrome version of a scrollbar arrow (dark) + if(fMouseDown) + { + SetBkColor(hdcmem2, GetSysColor(COLOR_BTNTEXT)); + BitBlt(hdcmem1, 0, 0, width, height, hdcmem2, 0, 0, SRCCOPY); + SetBkColor(hdc, 0x00ffffff); + SetTextColor(hdc, GetSysColor(COLOR_3DDKSHADOW)); + BitBlt(hdc, rect->left, rect->top, width, height, hdcmem1, 0, 0, SRCCOPY); + } + //draw a flat monochrome version of a scrollbar arrow (grey) + else if(fMouseOver) + { + SetBkColor(hdcmem2, GetSysColor(COLOR_BTNTEXT)); + FillRect(hdcmem1, &rc, reinterpret_cast(GetStockObject(WHITE_BRUSH))); + BitBlt(hdcmem1, 0, 0, width, height, hdcmem2, 0, 0, SRCINVERT); + + SetBkColor(hdc, GetSysColor(COLOR_3DSHADOW)); + SetTextColor(hdc, 0x00ffffff); + BitBlt(hdc, rect->left, rect->top, width, height, hdcmem1, 0, 0, SRCCOPY); + } + //draw the arrow normally + else + { + BitBlt(hdc, rect->left, rect->top, width, height, hdcmem2, 0, 0, SRCCOPY); + } + + SelectObject(hdcmem1, oldbm1); + SelectObject(hdcmem2, oldbm2); + DeleteObject(hbm1); + DeleteObject(hbm2); + DeleteDC(hdcmem1); + DeleteDC(hdcmem2); + + ret = 0; + } + else +#endif + ret = DrawFrameControl(hdc, rect, DFC_SCROLL, flags); + + return ret; +} + +// +// Return the size in pixels for the specified scrollbar metric, +// for the specified scrollbar +// +static int GetScrollMetric(SCROLLBAR *sbar, int metric) +{ + if(sbar->nBarType == SB_HORZ) + { + if(metric == SM_CXHORZSB) + { + if(sbar->nArrowLength < 0) + return -sbar->nArrowLength * GetSystemMetrics(SM_CXHSCROLL); + else + return sbar->nArrowLength; + } + else + { + if(sbar->nArrowWidth < 0) + return -sbar->nArrowWidth * GetSystemMetrics(SM_CYHSCROLL); + else + return sbar->nArrowWidth; + } + } + else if(sbar->nBarType == SB_VERT) + { + if(metric == SM_CYVERTSB) + { + if(sbar->nArrowLength < 0) + return -sbar->nArrowLength * GetSystemMetrics(SM_CYVSCROLL); + else + return sbar->nArrowLength; + } + else + { + if(sbar->nArrowWidth < 0) + return -sbar->nArrowWidth * GetSystemMetrics(SM_CXVSCROLL); + else + return sbar->nArrowWidth; + } + } + + return 0; +} + +// +// +// +static COLORREF GetSBForeColor(void) +{ + COLORREF c1 = GetSysColor(COLOR_3DHILIGHT); + COLORREF c2 = GetSysColor(COLOR_WINDOW); + + if(c1 != 0xffffff && c1 == c2) + { + return GetSysColor(COLOR_BTNFACE); + } + else + { + return GetSysColor(COLOR_3DHILIGHT); + } +} + +static COLORREF GetSBBackColor(void) +{ + return GetSysColor(COLOR_SCROLLBAR); +} + +// +// Paint a checkered rectangle, with each alternate +// pixel being assigned a different colour +// +static void DrawCheckedRect(HDC hdc, RECT *rect, COLORREF fg, COLORREF bg) +{ + static WORD wCheckPat[8] = + { + 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555 + }; + + HBITMAP hbmp; + HBRUSH hbr, hbrold; + COLORREF fgold, bgold; + + hbmp = CreateBitmap(8, 8, 1, 1, wCheckPat); + hbr = CreatePatternBrush(hbmp); + + UnrealizeObject(hbr); + SetBrushOrgEx(hdc, rect->left, rect->top, 0); + + hbrold = (HBRUSH)SelectObject(hdc, hbr); + + fgold = SetTextColor(hdc, fg); + bgold = SetBkColor(hdc, bg); + + PatBlt(hdc, rect->left, rect->top, + rect->right - rect->left, + rect->bottom - rect->top, + PATCOPY); + + SetBkColor(hdc, bgold); + SetTextColor(hdc, fgold); + + SelectObject(hdc, hbrold); + DeleteObject(hbr); + DeleteObject(hbmp); +} + +// +// Fill the specifed rectangle using a solid colour +// +static void PaintRect(HDC hdc, RECT *rect, COLORREF color) +{ + COLORREF oldcol = SetBkColor(hdc, color); + ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, rect, "", 0, NULL); + SetBkColor(hdc, oldcol); +} + +// +// Draw a simple blank scrollbar push-button. Can be used +// to draw a push button, or the scrollbar thumb +// drawflag - could set to BF_FLAT to make flat scrollbars +// +void DrawBlankButton(HDC hdc, const RECT *rect, UINT drawflag) +{ + RECT rc = *rect; + +#ifndef FLAT_SCROLLBARS + drawflag &= ~BF_FLAT; +#endif + + DrawEdge(hdc, &rc, EDGE_RAISED, BF_RECT | drawflag | BF_ADJUST); + FillRect(hdc, &rc, GetSysColorBrush(COLOR_BTNFACE)); +} + +// +// Send a WM_VSCROLL or WM_HSCROLL message +// +static void SendScrollMessage(HWND hwnd, UINT scrMsg, UINT scrId, UINT pos) +{ + SendMessage(hwnd, scrMsg, MAKEWPARAM(scrId, pos), 0); +} + +// +// Calculate the screen coordinates of the area taken by +// the horizontal scrollbar. Take into account the size +// of the window borders +// +static BOOL GetHScrollRect(SCROLLWND *sw, HWND hwnd, RECT *rect) +{ + GetWindowRect(hwnd, rect); + + if(sw->fLeftScrollbar) + { + rect->left += sw->cxLeftEdge + (sw->sbarVert.fScrollVisible ? + GetScrollMetric(&sw->sbarVert, SM_CXVERTSB) : 0); + rect->right -= sw->cxRightEdge; + } + else + { + rect->left += sw->cxLeftEdge; //left window edge + + rect->right -= sw->cxRightEdge + //right window edge + (sw->sbarVert.fScrollVisible ? + GetScrollMetric(&sw->sbarVert, SM_CXVERTSB) : 0); + } + + rect->bottom -= sw->cyBottomEdge; //bottom window edge + + rect->top = rect->bottom - + (sw->sbarHorz.fScrollVisible ? + GetScrollMetric(&sw->sbarHorz, SM_CYHORZSB) : 0); + + return TRUE; +} + +// +// Calculate the screen coordinates of the area taken by the +// vertical scrollbar +// +static BOOL GetVScrollRect(SCROLLWND *sw, HWND hwnd, RECT *rect) +{ + GetWindowRect(hwnd, rect); + rect->top += sw->cyTopEdge; //top window edge + + rect->bottom -= sw->cyBottomEdge + + (sw->sbarHorz.fScrollVisible ? //bottom window edge + GetScrollMetric(&sw->sbarHorz, SM_CYHORZSB) : 0); + + if(sw->fLeftScrollbar) + { + rect->left += sw->cxLeftEdge; + rect->right = rect->left + (sw->sbarVert.fScrollVisible ? + GetScrollMetric(&sw->sbarVert, SM_CXVERTSB) : 0); + } + else + { + rect->right -= sw->cxRightEdge; + rect->left = rect->right - (sw->sbarVert.fScrollVisible ? + GetScrollMetric(&sw->sbarVert, SM_CXVERTSB) : 0); + } + + return TRUE; +} + +// Depending on what type of scrollbar nBar refers to, call the +// appropriate Get?ScrollRect function +// +BOOL GetScrollRect(SCROLLWND *sw, UINT nBar, HWND hwnd, RECT *rect) +{ + if(nBar == SB_HORZ) + return GetHScrollRect(sw, hwnd, rect); + else if(nBar == SB_VERT) + return GetVScrollRect(sw, hwnd, rect); + else + return FALSE; +} + +// +// This code is a prime candidate for splitting out into a separate +// file at some stage +// +#ifdef INCLUDE_BUTTONS + +// +// Calculate the size in pixels of the specified button +// +static int GetSingleButSize(SCROLLBAR *sbar, SCROLLBUT *sbut) +{ + //multiple of the system button size + //or a specific button size + if(sbut->nSize < 0) + { + if(sbar->nBarType == SB_HORZ) + return -sbut->nSize * GetSystemMetrics(SM_CXHSCROLL); + else + return -sbut->nSize * GetSystemMetrics(SM_CYVSCROLL); + } + else + return sbut->nSize; +} + +// +// Find the size in pixels of all the inserted buttons, +// either before or after the specified scrollbar +// +static int GetButtonSize(SCROLLBAR *sbar, HWND hwnd, UINT uBeforeAfter) +{ + int i; + int nPixels = 0; + + SCROLLBUT *sbut = sbar->sbButtons; + + for(i = 0; i < sbar->nButtons; i++) + { + //only consider those buttons on the same side as nTopBottom says + if(sbut[i].uPlacement == uBeforeAfter) + { + nPixels += GetSingleButSize(sbar, &sbut[i]); + } + } + + return nPixels; +} +#endif //INCLUDE_BUTTONS + +// +// Work out the scrollbar width/height for either type of scrollbar (SB_HORZ/SB_VERT) +// rect - coords of the scrollbar. +// store results into *thumbsize and *thumbpos +// +static int CalcThumbSize(SCROLLBAR *sbar, const RECT *rect, int *pthumbsize, int *pthumbpos) +{ + SCROLLINFO *si; + int scrollsize; //total size of the scrollbar including arrow buttons + int workingsize; //working area (where the thumb can slide) + int siMaxMin; + int butsize; + int startcoord; + int thumbpos = 0, thumbsize = 0; + + int adjust=0; + static int count=0; + + //work out the width (for a horizontal) or the height (for a vertical) + //of a standard scrollbar button + butsize = GetScrollMetric(sbar, SM_SCROLL_LENGTH); + + if(1) //sbar->nBarType == SB_HORZ) + { + scrollsize = rect->right - rect->left; + startcoord = rect->left; + } + /*else if(sbar->nBarType == SB_VERT) + { + scrollsize = rect->bottom - rect->top; + startcoord = rect->top; + } + else + { + return 0; + }*/ + + si = &sbar->scrollInfo; + siMaxMin = si->nMax - si->nMin + 1; + workingsize = scrollsize - butsize * 2; + + // + // Work out the scrollbar thumb SIZE + // + if(si->nPage == 0) + { + thumbsize = butsize; + } + else if(siMaxMin > 0) + { + thumbsize = MulDiv(si->nPage, workingsize, siMaxMin); + + if(thumbsize < sbar->nMinThumbSize) + thumbsize = sbar->nMinThumbSize; + } + + // + // Work out the scrollbar thumb position + // + if(siMaxMin > 0) + { + int pagesize = max(1, si->nPage); + thumbpos = MulDiv(si->nPos - si->nMin, workingsize-thumbsize, siMaxMin - pagesize); + + if(thumbpos < 0) + thumbpos = 0; + + if(thumbpos >= workingsize-thumbsize) + thumbpos = workingsize-thumbsize; + } + + thumbpos += startcoord + butsize; + + *pthumbpos = thumbpos; + *pthumbsize = thumbsize; + + return 1; +} + +// +// return a hit-test value for whatever part of the scrollbar x,y is located in +// rect, x, y: SCREEN coordinates +// the rectangle must not include space for any inserted buttons +// (i.e, JUST the scrollbar area) +// +static UINT GetHorzScrollPortion(SCROLLBAR *sbar, HWND hwnd, const RECT *rect, int x, int y) +{ + int thumbwidth, thumbpos; + int butwidth = GetScrollMetric(sbar, SM_SCROLL_LENGTH); + int scrollwidth = rect->right-rect->left; + int workingwidth = scrollwidth - butwidth*2; + + if(y < rect->top || y >= rect->bottom) + return HTSCROLL_NONE; + + CalcThumbSize(sbar, rect, &thumbwidth, &thumbpos); + + //if we have had to scale the buttons to fit in the rect, + //then adjust the button width accordingly + if(scrollwidth <= butwidth * 2) + { + butwidth = scrollwidth / 2; + } + + //check for left button click + if(x >= rect->left && x < rect->left + butwidth) + { + return HTSCROLL_LEFT; + } + //check for right button click + else if(x >= rect->right-butwidth && x < rect->right) + { + return HTSCROLL_RIGHT; + } + + //if the thumb is too big to fit (i.e. it isn't visible) + //then return a NULL scrollbar area + if(thumbwidth >= workingwidth) + return HTSCROLL_NONE; + + //check for point in the thumbbar + if(x >= thumbpos && x < thumbpos+thumbwidth) + { + return HTSCROLL_THUMB; + } + //check for left margin + else if(x >= rect->left+butwidth && x < thumbpos) + { + return HTSCROLL_PAGELEFT; + } + else if(x >= thumbpos+thumbwidth && x < rect->right-butwidth) + { + return HTSCROLL_PAGERIGHT; + } + + return HTSCROLL_NONE; +} + +// +// For vertical scrollbars, rotate all coordinates by -90 degrees +// so that we can use the horizontal version of this function +// +static UINT GetVertScrollPortion(SCROLLBAR *sb, HWND hwnd, RECT *rect, int x, int y) +{ + UINT r; + + RotateRect(rect); + r = GetHorzScrollPortion(sb, hwnd, rect, y, x); + RotateRect(rect); + return r; +} + +// +// CUSTOM DRAW support +// +static LRESULT PostCustomPrePostPaint(HWND hwnd, HDC hdc, SCROLLBAR *sb, UINT dwStage) +{ +#ifdef CUSTOM_DRAW + NMCSBCUSTOMDRAW nmcd; + + CoolSB_ZeroMemory(&nmcd, sizeof nmcd); + nmcd.hdr.hwndFrom = hwnd; + nmcd.hdr.idFrom = GetWindowLongPtr(hwnd, GWLP_ID); + nmcd.hdr.code = NM_COOLSB_CUSTOMDRAW; + nmcd.nBar = sb->nBarType; + nmcd.dwDrawStage = dwStage; + nmcd.hdc = hdc; + + hwnd = GetParent(hwnd); + return CustomDrawScrollBars(&nmcd); +#else + return 0; +#endif +} + +static LRESULT PostCustomDrawNotify(HWND hwnd, HDC hdc, UINT nBar, RECT *prect, UINT nItem, BOOL fMouseDown, BOOL fMouseOver, BOOL fInactive) +{ +#ifdef CUSTOM_DRAW + NMCSBCUSTOMDRAW nmcd; + + //fill in the standard header + nmcd.hdr.hwndFrom = hwnd; + nmcd.hdr.idFrom = GetWindowLongPtr(hwnd, GWLP_ID); + nmcd.hdr.code = NM_COOLSB_CUSTOMDRAW; + + nmcd.dwDrawStage = CDDS_ITEMPREPAINT; + nmcd.nBar = nBar; + nmcd.rect = *prect; + nmcd.uItem = nItem; + nmcd.hdc = hdc; + + if(fMouseDown) + nmcd.uState = CDIS_SELECTED; + else if(fMouseOver) + nmcd.uState = CDIS_HOT; + else if(fInactive) + nmcd.uState = CDIS_DISABLED; + else + nmcd.uState = CDIS_DEFAULT; + + hwnd = GetParent(hwnd); + return CustomDrawScrollBars(&nmcd); +#else + return 0; +#endif +} + +// Depending on if we are supporting custom draw, either define +// a macro to the function name, or to nothing at all. If custom draw +// is turned off, then we can save ALOT of code space by binning all +// calls to the custom draw support. + +/* +#ifdef CUSTOM_DRAW +#define PostCustomDrawNotify PostCustomDrawNotify0 +#define PostCustomPrePostPaint PostCustomPrePostPaint0 +#else +#define PostCustomDrawNotify 1 ? (void)0 : PostCustomDrawNotify0 +#define PostCustomPrePostPaint 1 ? (void)0 : PostCustomPrePostPaint0 +#endif +*/ + +static LRESULT PostMouseNotify0(HWND hwnd, UINT msg, UINT nBar, RECT *prect, UINT nCmdId, POINT pt) +{ +#ifdef NOTIFY_MOUSE + NMCOOLBUTMSG nmcb; + + //fill in the standard header + nmcb.hdr.hwndFrom = hwnd; + nmcb.hdr.idFrom = GetWindowLongPtr(hwnd, GWLP_ID); + nmcb.hdr.code = NM_CLICK; + + nmcb.nBar = nBar; + nmcb.uCmdId = nCmdId; + nmcb.uState = 0; + nmcb.rect = *prect; + nmcb.pt = pt; + + hwnd = GetParent(hwnd); + return SendMessage(hwnd, WM_NOTIFY, nmcb.hdr.idFrom, (LPARAM)&nmcb); +#else + return 0; +#endif +} + +#ifdef NOTIFY_MOUSE +#define PostMouseNotify PostMouseNotify0 +#else +#define PostMouseNotify 1 ? (void)0 : PostMouseNotify0 +#endif + + + +// +// Draw a complete HORIZONTAL scrollbar in the given rectangle +// Don't draw any inserted buttons in this procedure +// +// uDrawFlags - hittest code, to say if to draw the +// specified portion in an active state or not. +// +// +static LRESULT NCDrawHScrollbar(SCROLLBAR *sb, HWND hwnd, HDC hdc, const RECT *rect, UINT uDrawFlags) +{ + SCROLLINFO *si; + RECT ctrl, thumb; + RECT sbm; + int butwidth = GetScrollMetric(sb, SM_SCROLL_LENGTH); + int scrollwidth = rect->right-rect->left; + int workingwidth = scrollwidth - butwidth*2; + int thumbwidth = 0, thumbpos = 0; + int siMaxMin; + + BOOL fCustomDraw = 0; + + BOOL fMouseDownL = 0, fMouseOverL = 0, fBarHot = 0; + BOOL fMouseDownR = 0, fMouseOverR = 0; + + COLORREF crCheck1 = GetSBForeColor(); + COLORREF crCheck2 = GetSBBackColor(); + COLORREF crInverse1 = InvertCOLORREF(crCheck1); + COLORREF crInverse2 = InvertCOLORREF(crCheck2); + + UINT uDFCFlat = sb->fFlatScrollbar ? DFCS_FLAT : 0; + UINT uDEFlat = sb->fFlatScrollbar ? BF_FLAT : 0; + + //drawing flags to modify the appearance of the scrollbar buttons + UINT uLeftButFlags = DFCS_SCROLLLEFT; + UINT uRightButFlags = DFCS_SCROLLRIGHT; + + if(scrollwidth <= 0) + return 0; + + si = &sb->scrollInfo; + siMaxMin = si->nMax - si->nMin; + + if(hwnd != hwndCurCoolSB) + uDrawFlags = HTSCROLL_NONE; + // + // work out the thumb size and position + // + CalcThumbSize(sb, rect, &thumbwidth, &thumbpos); + + if(sb->fScrollFlags & ESB_DISABLE_LEFT) uLeftButFlags |= DFCS_INACTIVE; + if(sb->fScrollFlags & ESB_DISABLE_RIGHT) uRightButFlags |= DFCS_INACTIVE; + + //if we need to grey the arrows because there is no data to scroll + if(!IsScrollInfoActive(si) && !(sb->fScrollFlags & CSBS_THUMBALWAYS)) + { + uLeftButFlags |= DFCS_INACTIVE; + uRightButFlags |= DFCS_INACTIVE; + } + + if(hwnd == hwndCurCoolSB) + { +#ifdef FLAT_SCROLLBARS + BOOL ldis = !(uLeftButFlags & DFCS_INACTIVE); + BOOL rdis = !(uRightButFlags & DFCS_INACTIVE); + + fBarHot = (sb->nBarType == (int)uMouseOverScrollbar && sb->fFlatScrollbar == CSBS_HOTTRACKED); + + fMouseOverL = uHitTestPortion == HTSCROLL_LEFT && fBarHot && ldis; + fMouseOverR = uHitTestPortion == HTSCROLL_RIGHT && fBarHot && rdis; +#endif + fMouseDownL = (uDrawFlags == HTSCROLL_LEFT); + fMouseDownR = (uDrawFlags == HTSCROLL_RIGHT); + } + + +//#ifdef CUSTOM_DRAW + fCustomDraw = ((PostCustomPrePostPaint(hwnd, hdc, sb, CDDS_PREPAINT)) == CDRF_SKIPDEFAULT); +//#endif + + // + // Draw the scrollbar now + // + if(scrollwidth > butwidth*2) + { + //LEFT ARROW + SetRect(&ctrl, rect->left, rect->top, rect->left + butwidth, rect->bottom); + + RotateRect0(sb, &ctrl); + + if(fCustomDraw) + PostCustomDrawNotify(hwnd, hdc, sb->nBarType, &ctrl, SB_LINELEFT, fMouseDownL, fMouseOverL, uLeftButFlags & DFCS_INACTIVE); + else + DrawScrollArrow(sb, hdc, &ctrl, uLeftButFlags, fMouseDownL, fMouseOverL); + + RotateRect0(sb, &ctrl); + + //MIDDLE PORTION + //if we can fit the thumbbar in, then draw it + if(thumbwidth > 0 && thumbwidth <= workingwidth + && IsScrollInfoActive(si) && ((sb->fScrollFlags & ESB_DISABLE_BOTH) != ESB_DISABLE_BOTH)) + { + //Draw the scrollbar margin above the thumb + SetRect(&sbm, rect->left + butwidth, rect->top, thumbpos, rect->bottom); + + RotateRect0(sb, &sbm); + + if(fCustomDraw) + { + PostCustomDrawNotify(hwnd, hdc, sb->nBarType, &sbm, SB_PAGELEFT, uDrawFlags == HTSCROLL_PAGELEFT, FALSE, FALSE); + } + else + { + if(uDrawFlags == HTSCROLL_PAGELEFT) + DrawCheckedRect(hdc, &sbm, crInverse1, crInverse2); + else + DrawCheckedRect(hdc, &sbm, crCheck1, crCheck2); + + } + + RotateRect0(sb, &sbm); + + //Draw the margin below the thumb + sbm.left = thumbpos+thumbwidth; + sbm.right = rect->right - butwidth; + + RotateRect0(sb, &sbm); + if(fCustomDraw) + { + PostCustomDrawNotify(hwnd, hdc, sb->nBarType, &sbm, SB_PAGERIGHT, uDrawFlags == HTSCROLL_PAGERIGHT, 0, 0); + } + else + { + if(uDrawFlags == HTSCROLL_PAGERIGHT) + DrawCheckedRect(hdc, &sbm, crInverse1, crInverse2); + else + DrawCheckedRect(hdc, &sbm, crCheck1, crCheck2); + + } + RotateRect0(sb, &sbm); + + //Draw the THUMB finally + SetRect(&thumb, thumbpos, rect->top, thumbpos+thumbwidth, rect->bottom); + + RotateRect0(sb, &thumb); + + if(fCustomDraw) + { + PostCustomDrawNotify(hwnd, hdc, sb->nBarType, &thumb, SB_THUMBTRACK, uDrawFlags==HTSCROLL_THUMB, uHitTestPortion == HTSCROLL_THUMB && fBarHot, FALSE); + } + else + { + +#ifdef FLAT_SCROLLBARS + if(hwnd == hwndCurCoolSB && sb->fFlatScrollbar && (uDrawFlags == HTSCROLL_THUMB || + (uHitTestPortion == HTSCROLL_THUMB && fBarHot))) + { + PaintRect(hdc, &thumb, GetSysColor(COLOR_3DSHADOW)); + } + else +#endif + { + DrawBlankButton(hdc, &thumb, uDEFlat); + } + } + RotateRect0(sb, &thumb); + + } + //otherwise, just leave that whole area blank + else + { + OffsetRect(&ctrl, butwidth, 0); + ctrl.right = rect->right - butwidth; + + //if we always show the thumb covering the whole scrollbar, + //then draw it that way + if(!IsScrollInfoActive(si) && (sb->fScrollFlags & CSBS_THUMBALWAYS) + && ctrl.right - ctrl.left > sb->nMinThumbSize) + { + //leave a 1-pixel gap between the thumb + right button + ctrl.right --; + RotateRect0(sb, &ctrl); + + if(fCustomDraw) + PostCustomDrawNotify(hwnd, hdc, sb->nBarType, &ctrl, SB_THUMBTRACK, fMouseDownL, FALSE, FALSE); + else + { +#ifdef FLAT_SCROLLBARS + if(sb->fFlatScrollbar == CSBS_HOTTRACKED && uDrawFlags == HTSCROLL_THUMB) + PaintRect(hdc, &ctrl, GetSysColor(COLOR_3DSHADOW)); + else +#endif + DrawBlankButton(hdc, &ctrl, uDEFlat); + + } + RotateRect0(sb, &ctrl); + + //draw the single-line gap + ctrl.left = ctrl.right; + ctrl.right += 1; + + RotateRect0(sb, &ctrl); + + if(fCustomDraw) + PostCustomDrawNotify(hwnd, hdc, sb->nBarType, &ctrl, SB_PAGERIGHT, 0, 0, 0); + else + PaintRect(hdc, &ctrl, GetSysColor(COLOR_SCROLLBAR)); + + RotateRect0(sb, &ctrl); + } + //otherwise, paint a blank if the thumb doesn't fit in + else + { + RotateRect0(sb, &ctrl); + + if(fCustomDraw) + PostCustomDrawNotify(hwnd, hdc, sb->nBarType, &ctrl, SB_PAGERIGHT, 0, 0, 0); + else + DrawCheckedRect(hdc, &ctrl, crCheck1, crCheck2); + + RotateRect0(sb, &ctrl); + } + } + + //RIGHT ARROW + SetRect(&ctrl, rect->right - butwidth, rect->top, rect->right, rect->bottom); + + RotateRect0(sb, &ctrl); + + if(fCustomDraw) + PostCustomDrawNotify(hwnd, hdc, sb->nBarType, &ctrl, SB_LINERIGHT, fMouseDownR, fMouseOverR, uRightButFlags & DFCS_INACTIVE); + else + DrawScrollArrow(sb, hdc, &ctrl, uRightButFlags, fMouseDownR, fMouseOverR); + + RotateRect0(sb, &ctrl); + } + //not enough room for the scrollbar, so just draw the buttons (scaled in size to fit) + else + { + butwidth = scrollwidth / 2; + + //LEFT ARROW + SetRect(&ctrl, rect->left, rect->top, rect->left + butwidth, rect->bottom); + + RotateRect0(sb, &ctrl); + if(fCustomDraw) + PostCustomDrawNotify(hwnd, hdc, sb->nBarType, &ctrl, SB_LINELEFT, fMouseDownL, fMouseOverL, uLeftButFlags & DFCS_INACTIVE); + else + DrawScrollArrow(sb, hdc, &ctrl, uLeftButFlags, fMouseDownL, fMouseOverL); + RotateRect0(sb, &ctrl); + + //RIGHT ARROW + OffsetRect(&ctrl, scrollwidth - butwidth, 0); + + RotateRect0(sb, &ctrl); + if(fCustomDraw) + PostCustomDrawNotify(hwnd, hdc, sb->nBarType, &ctrl, SB_LINERIGHT, fMouseDownR, fMouseOverR, uRightButFlags & DFCS_INACTIVE); + else + DrawScrollArrow(sb, hdc, &ctrl, uRightButFlags, fMouseDownR, fMouseOverR); + RotateRect0(sb, &ctrl); + + //if there is a gap between the buttons, fill it with a solid color + //if(butwidth & 0x0001) + if(ctrl.left != rect->left + butwidth) + { + ctrl.left --; + ctrl.right -= butwidth; + RotateRect0(sb, &ctrl); + + if(fCustomDraw) + PostCustomDrawNotify(hwnd, hdc, sb->nBarType, &ctrl, SB_PAGERIGHT, 0, 0, 0); + else + DrawCheckedRect(hdc, &ctrl, crCheck1, crCheck2); + + RotateRect0(sb, &ctrl); + } + + } + +//#ifdef CUSTOM_DRAW + PostCustomPrePostPaint(hwnd, hdc, sb, CDDS_POSTPAINT); +//#endif + + return fCustomDraw; +} + +// +// Draw a vertical scrollbar using the horizontal draw routine, but +// with the coordinates adjusted accordingly +// +static LRESULT NCDrawVScrollbar(SCROLLBAR *sb, HWND hwnd, HDC hdc, const RECT *rect, UINT uDrawFlags) +{ + LRESULT ret; + RECT rc; + + rc = *rect; + RotateRect(&rc); + ret = NCDrawHScrollbar(sb, hwnd, hdc, &rc, uDrawFlags); + RotateRect(&rc); + + return ret; +} + +// +// Generic wrapper function for the scrollbar drawing +// +static LRESULT NCDrawScrollbar(SCROLLBAR *sb, HWND hwnd, HDC hdc, const RECT *rect, UINT uDrawFlags) +{ + if(sb->nBarType == SB_HORZ) + return NCDrawHScrollbar(sb, hwnd, hdc, rect, uDrawFlags); + else + return NCDrawVScrollbar(sb, hwnd, hdc, rect, uDrawFlags); +} + +#ifdef INCLUDE_BUTTONS + +// +// Draw the specified bitmap centered in the rectangle +// +static void DrawImage(HDC hdc, HBITMAP hBitmap, RECT *rc) +{ + BITMAP bm; + int cx; + int cy; + HDC memdc; + HBITMAP hOldBM; + RECT rcDest = *rc; + POINT p; + SIZE delta; + COLORREF colorOld; + + if(hBitmap == NULL) + return; + + // center bitmap in caller's rectangle + GetObject(hBitmap, sizeof bm, &bm); + + cx = bm.bmWidth; + cy = bm.bmHeight; + + delta.cx = (rc->right-rc->left - cx) / 2; + delta.cy = (rc->bottom-rc->top - cy) / 2; + + if(rc->right-rc->left > cx) + { + SetRect(&rcDest, rc->left+delta.cx, rc->top + delta.cy, 0, 0); + rcDest.right = rcDest.left + cx; + rcDest.bottom = rcDest.top + cy; + p.x = 0; + p.y = 0; + } + else + { + p.x = -delta.cx; + p.y = -delta.cy; + } + + // select checkmark into memory DC + memdc = CreateCompatibleDC(hdc); + hOldBM = (HBITMAP)SelectObject(memdc, hBitmap); + + // set BG color based on selected state + colorOld = SetBkColor(hdc, GetSysColor(COLOR_3DFACE)); + + BitBlt(hdc, rcDest.left, rcDest.top, rcDest.right-rcDest.left, rcDest.bottom-rcDest.top, memdc, p.x, p.y, SRCCOPY); + + // restore + SetBkColor(hdc, colorOld); + SelectObject(memdc, hOldBM); + DeleteDC(memdc); +} + +// +// Draw the specified metafile +// +static void DrawMetaFile(HDC hdc, HENHMETAFILE hemf, RECT *rect) +{ + RECT rc; + POINT pt; + + SetRect(&rc, 0, 0, rect->right-rect->left, rect->bottom-rect->top); + SetWindowOrgEx(hdc, -rect->left, -rect->top, &pt); + PlayEnhMetaFile(hdc, hemf, &rc); + SetWindowOrgEx(hdc, pt.x, pt.y, 0); +} + +// +// Draw a single scrollbar inserted button, in whatever style +// it has been defined to use. +// +static UINT DrawScrollButton(SCROLLBUT *sbut, HDC hdc, const RECT *pctrl, UINT flags) +{ + NMCSBCUSTOMDRAW nmcd; + HWND hwnd; + RECT rect = *pctrl; + UINT f; + + switch(sbut->uButType & SBBT_MASK) + { + case SBBT_OWNERDRAW: + + hwnd = WindowFromDC(hdc); + + //fill in the standard header + nmcd.hdr.hwndFrom = hwnd; + nmcd.hdr.idFrom = GetWindowLongPtr(hwnd, GWLP_ID); + nmcd.hdr.code = NM_COOLSB_CUSTOMDRAW; + + nmcd.dwDrawStage = CDDS_ITEMPREPAINT; + nmcd.nBar = SB_INSBUT; + nmcd.rect = *pctrl; + nmcd.uItem = sbut->uCmdId; + nmcd.hdc = hdc; + nmcd.uState = flags; + + IntersectClipRect(hdc, rect.left, rect.top, rect.right, rect.bottom); + SendMessage(GetParent(hwnd), WM_NOTIFY, nmcd.hdr.idFrom, (LPARAM)&nmcd); + SelectClipRgn(hdc, NULL); + + break; + + case SBBT_FIXED: + flags &= ~SBBS_PUSHED; + + case SBBT_TOGGLEBUTTON: + if(sbut->uState != SBBS_NORMAL) + flags |= SBBS_PUSHED; + + //intentionally fall through here... + + case SBBT_PUSHBUTTON: + + f = flags & SBBS_PUSHED ? DFCS_PUSHED | DFCS_FLAT : 0; + if(sbut->uButType & SBBM_LEFTARROW) + { + DrawFrameControl(hdc, &rect, DFC_SCROLL, DFCS_SCROLLLEFT | f); + } + else if(sbut->uButType & SBBM_RIGHTARROW) + { + DrawFrameControl(hdc, &rect, DFC_SCROLL, DFCS_SCROLLRIGHT | f); + } + else if(sbut->uButType & SBBM_UPARROW) + { + DrawFrameControl(hdc, &rect, DFC_SCROLL, DFCS_SCROLLUP | f); + } + else if(sbut->uButType & SBBM_DOWNARROW) + { + DrawFrameControl(hdc, &rect, DFC_SCROLL, DFCS_SCROLLDOWN | f); + } + else + { + // + if(flags & SBBS_PUSHED) + { + if(sbut->uButType & SBBM_RECESSED) + { + InflateRect(&rect, -1, -1); + DrawEdge(hdc, &rect, EDGE_SUNKEN, BF_RECT|BF_FLAT); + InflateRect(&rect, 1, 1); + + FrameRect(hdc, &rect, GetSysColorBrush(COLOR_3DDKSHADOW)); + InflateRect(&rect, -2, -2); + } + else + { + DrawEdge(hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_FLAT | BF_ADJUST); + InflateRect(&rect, 1, 1); + } + } + else + { + // draw the button borders + if(sbut->uButType & SBBM_TYPE2) + { + DrawFrameControl(hdc, &rect, DFC_BUTTON, DFCS_BUTTONPUSH); + InflateRect(&rect, -2, -2); + } + + else if(sbut->uButType & SBBM_TYPE3) + { + DrawFrameControl(hdc, &rect, DFC_BUTTON, DFCS_BUTTONPUSH); + InflateRect(&rect, -1, -1); + } + else + { + DrawEdge(hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST); + rect.bottom++; + rect.right++; + } + + OffsetRect(&rect, -1, -1); + rect.top++; rect.left++; + } + + if(sbut->hBmp) + { + PaintRect(hdc, &rect, GetSysColor(COLOR_3DFACE)); + + if(flags & SBBS_PUSHED) + { + rect.top++; rect.left++; + } + + IntersectClipRect(hdc, rect.left, rect.top, rect.right,rect.bottom); + DrawImage(hdc, sbut->hBmp, &rect); + SelectClipRgn(hdc, 0); + } + else if(sbut->hEmf) + { + PaintRect(hdc, &rect, GetSysColor(COLOR_3DFACE)); + InflateRect(&rect, -1, -1); + + if(flags & SBBS_PUSHED) + { + rect.top++; rect.left++; + } + + IntersectClipRect(hdc, rect.left, rect.top, rect.right,rect.bottom); + DrawMetaFile(hdc, sbut->hEmf, &rect); + SelectClipRgn(hdc, 0); + } + else + { + PaintRect(hdc, &rect, GetSysColor(COLOR_3DFACE)); + } + } + + + break; + + case SBBT_BLANK: + PaintRect(hdc, &rect, GetSysColor(COLOR_3DFACE)); + break; + + case SBBT_FLAT: + DrawBlankButton(hdc, &rect, BF_FLAT); + break; + + case SBBT_DARK: + PaintRect(hdc, &rect, GetSysColor(COLOR_3DDKSHADOW)); + break; + } + + return 0; +} + +// +// Draw any buttons inserted into the horizontal scrollbar +// assume that the button widths have already been calculated +// Note: RECT *rect is the rectangle of the scrollbar +// leftright: 1 = left, 2 = right, 3 = both +// +static LRESULT DrawHorzButtons(SCROLLBAR *sbar, HDC hdc, const RECT *rect, int leftright) +{ + int i; + int xposl, xposr; + RECT ctrl; + SCROLLBUT *sbut = sbar->sbButtons; + + xposl = rect->left - sbar->nButSizeBefore; + xposr = rect->right; + + for(i = 0; i < sbar->nButtons; i++) + { + if((leftright & SBBP_LEFT) && sbut[i].uPlacement == SBBP_LEFT) + { + int butwidth = GetSingleButSize(sbar, &sbut[i]); + SetRect(&ctrl, xposl, rect->top, xposl + butwidth, rect->bottom); + RotateRect0(sbar, &ctrl); + DrawScrollButton(&sbut[i], hdc, &ctrl, SBBS_NORMAL); + + xposl += butwidth; + } + + if((leftright & SBBP_RIGHT) && sbut[i].uPlacement == SBBP_RIGHT) + { + int butwidth = GetSingleButSize(sbar, &sbut[i]); + SetRect(&ctrl, xposr, rect->top, xposr + butwidth, rect->bottom); + RotateRect0(sbar, &ctrl); + DrawScrollButton(&sbut[i], hdc, &ctrl, SBBS_NORMAL); + xposr += butwidth; + } + } + return 0; +} + +static LRESULT DrawVertButtons(SCROLLBAR *sbar, HDC hdc, const RECT *rect, int leftright) +{ + RECT rc = *rect; + RotateRect(&rc); + DrawHorzButtons(sbar, hdc, &rc, leftright); + return 0; +} +#endif // INCLUDE_BUTTONS + +// +// Define these two for proper processing of NCPAINT +// NOT needed if we don't bother to mask the scrollbars we draw +// to prevent the old window procedure from accidently drawing over them +// +HDC CoolSB_GetDC(HWND hwnd, WPARAM wParam) +{ + // I just can't figure out GetDCEx, so I'll just use this: + return GetWindowDC(hwnd); + + /* + RECT rc; + DWORD flags = 0x10000; + HRGN hrgn = (HRGN)wParam; + + if(hrgn == (HRGN)1) + { + GetWindowRect(hwnd, &rc); + OffsetRect(&rc, -rc.left, -rc.top); + hrgn = CreateRectRgnIndirect(&rc); + } + + if(GetWindowLongPtr(hwnd, GWL_STYLE) & WS_CLIPCHILDREN) + flags |= DCX_CLIPCHILDREN; + + if(GetWindowLongPtr(hwnd, GWL_STYLE) & WS_CLIPSIBLINGS) + flags |= DCX_CLIPSIBLINGS; + + return GetDCEx(hwnd, hrgn, flags | DCX_CACHE|DCX_NORESETATTRS|DCX_WINDOW | DCX_INTERSECTUPDATE); + */ + //return GetDCEx(hwnd, NULL, flags | DCX_WINDOW| DCX_NORESETATTRS); +} + +static LRESULT NCPaint(SCROLLWND *sw, HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + SCROLLBAR *sb; + HDC hdc; + HRGN hrgn; + RECT winrect, rect; + HRGN clip = 0; + BOOL fUpdateAll = ((LONG)wParam == 1); + BOOL fCustomDraw = FALSE; + LRESULT ret; + DWORD dwStyle; + + GetWindowRect(hwnd, &winrect); + + //if entire region needs painting, then make a region to cover the entire window + if(fUpdateAll) + hrgn = (HRGN)wParam; + else + hrgn = (HRGN)wParam; + + //hdc = GetWindowDC(hwnd); + hdc = CoolSB_GetDC(hwnd, wParam); + + // + // Only draw the horizontal scrollbar if the window is tall enough + // + sb = &sw->sbarHorz; + if(sb->fScrollVisible) + { + int hbarwidth = 0, leftright = 0; + + //get the screen coordinates of the whole horizontal scrollbar area + GetHScrollRect(sw, hwnd, &rect); + + //make the coordinates relative to the window for drawing + OffsetRect(&rect, -winrect.left, -winrect.top); + +#ifdef INCLUDE_BUTTONS + + //work out the size of any inserted buttons so we can dra them + sb->nButSizeBefore = GetButtonSize(sb, hwnd, SBBP_LEFT); + sb->nButSizeAfter = GetButtonSize(sb, hwnd, SBBP_RIGHT); + + //make sure there is room for the buttons + hbarwidth = rect.right - rect.left; + + //check that we can fit any left/right buttons in the available space + if(sb->nButSizeAfter < (hbarwidth - MIN_COOLSB_SIZE)) + { + //adjust the scrollbar rectangle to fit the buttons into + sb->fButVisibleAfter = TRUE; + rect.right -= sb->nButSizeAfter; + leftright |= SBBP_RIGHT; + + //check that there is enough space for the right buttons + if(sb->nButSizeBefore + sb->nButSizeAfter < (hbarwidth - MIN_COOLSB_SIZE)) + { + sb->fButVisibleBefore = TRUE; + rect.left += sb->nButSizeBefore; + leftright |= SBBP_LEFT; + } + else + sb->fButVisibleBefore = FALSE; + } + else + sb->fButVisibleAfter = FALSE; + + + DrawHorzButtons(sb, hdc, &rect, leftright); +#endif// INCLUDE_BUTTONS + + if(uCurrentScrollbar == SB_HORZ) + fCustomDraw |= NCDrawHScrollbar(sb, hwnd, hdc, &rect, uScrollTimerPortion); + else + fCustomDraw |= NCDrawHScrollbar(sb, hwnd, hdc, &rect, HTSCROLL_NONE); + } + + // + // Only draw the vertical scrollbar if the window is wide enough to accomodate it + // + sb = &sw->sbarVert; + if(sb->fScrollVisible) + { + int vbarheight = 0, updown = 0; + + //get the screen cooridinates of the whole horizontal scrollbar area + GetVScrollRect(sw, hwnd, &rect); + + //make the coordinates relative to the window for drawing + OffsetRect(&rect, -winrect.left, -winrect.top); + +#ifdef INCLUDE_BUTTONS + + //work out the size of any inserted buttons so we can dra them + sb->nButSizeBefore = GetButtonSize(sb, hwnd, SBBP_LEFT); + sb->nButSizeAfter = GetButtonSize(sb, hwnd, SBBP_RIGHT); + + //make sure there is room for the buttons + vbarheight = rect.bottom - rect.top; + + //check that we can fit any left/right buttons in the available space + if(sb->nButSizeAfter < (vbarheight - MIN_COOLSB_SIZE)) + { + //adjust the scrollbar rectangle to fit the buttons into + sb->fButVisibleAfter = TRUE; + rect.bottom -= sb->nButSizeAfter; + updown |= SBBP_BOTTOM; + + //check that there is enough space for the right buttons + if(sb->nButSizeBefore + sb->nButSizeAfter < (vbarheight - MIN_COOLSB_SIZE)) + { + sb->fButVisibleBefore = TRUE; + rect.top += sb->nButSizeBefore; + updown |= SBBP_TOP; + } + else + sb->fButVisibleBefore = FALSE; + } + else + sb->fButVisibleAfter = FALSE; + + + DrawVertButtons(sb, hdc, &rect, updown); +#endif // INCLUDE_BUTTONS + + if(uCurrentScrollbar == SB_VERT) + fCustomDraw |= NCDrawVScrollbar(sb, hwnd, hdc, &rect, uScrollTimerPortion); + else + fCustomDraw |= NCDrawVScrollbar(sb, hwnd, hdc, &rect, HTSCROLL_NONE); + } + + //Call the default window procedure for WM_NCPAINT, with the + //new window region. ** region must be in SCREEN coordinates ** + dwStyle = GetWindowLong(hwnd, GWL_STYLE); + + // If the window has WS_(H-V)SCROLL bits set, we should reset them + // to avoid windows taking the scrollbars into account. + // We temporarily set a flag preventing the subsecuent + // WM_STYLECHANGING/WM_STYLECHANGED to be forwarded to + // the original window procedure + if ( dwStyle & (WS_VSCROLL|WS_HSCROLL) ) + { + sw->bPreventStyleChange = TRUE; + SetWindowLong(hwnd, GWL_STYLE, dwStyle & ~(WS_VSCROLL|WS_HSCROLL)); + } + + ret = CallWindowProc(sw->oldproc, hwnd, WM_NCPAINT, (WPARAM)hrgn, lParam); + + if ( dwStyle & (WS_VSCROLL|WS_HSCROLL) ) + { + SetWindowLong(hwnd, GWL_STYLE, dwStyle); + sw->bPreventStyleChange = FALSE; + } + + + // DRAW THE DEAD AREA + // only do this if the horizontal and vertical bars are visible + if(sw->sbarHorz.fScrollVisible && sw->sbarVert.fScrollVisible) + { + GetWindowRect(hwnd, &rect); + OffsetRect(&rect, -winrect.left, -winrect.top); + + rect.bottom -= sw->cyBottomEdge; + rect.top = rect.bottom - GetScrollMetric(&sw->sbarHorz, SM_CYHORZSB); + + if(sw->fLeftScrollbar) + { + rect.left += sw->cxLeftEdge; + rect.right = rect.left + GetScrollMetric(&sw->sbarVert, SM_CXVERTSB); + } + else + { + rect.right -= sw->cxRightEdge; + rect.left = rect.right - GetScrollMetric(&sw->sbarVert, SM_CXVERTSB); + } + + if(fCustomDraw) + PostCustomDrawNotify(hwnd, hdc, SB_BOTH, &rect, 32, 0, 0, 0); + else + { + //calculate the position of THIS window's dead area + //with the position of the PARENT window's client rectangle. + //if THIS window has been positioned such that its bottom-right + //corner sits in the parent's bottom-right corner, then we should + //show the sizing-grip. + //Otherwise, assume this window is not in the right place, and + //just draw a blank rectangle + RECT parent; + RECT rect2; + HWND hwndParent = GetParent(hwnd); + + GetClientRect(hwndParent, &parent); + MapWindowPoints(hwndParent, 0, (POINT *)&parent, 2); + + CopyRect(&rect2, &rect); + OffsetRect(&rect2, winrect.left, winrect.top); + + if(!sw->fLeftScrollbar && parent.right == rect2.right+sw->cxRightEdge && parent.bottom == rect2.bottom+sw->cyBottomEdge + || sw->fLeftScrollbar && parent.left == rect2.left -sw->cxLeftEdge && parent.bottom == rect2.bottom+sw->cyBottomEdge) + DrawFrameControl(hdc, &rect, DFC_SCROLL, sw->fLeftScrollbar ? DFCS_SCROLLSIZEGRIPRIGHT : DFCS_SCROLLSIZEGRIP ); + else + PaintRect(hdc, &rect, GetSysColor(COLOR_3DFACE)); + } + } + + UNREFERENCED_PARAMETER(clip); + ReleaseDC(hwnd, hdc); + return ret; +} + +// +// Need to detect if we have clicked in the scrollbar region or not +// +static LRESULT NCHitTest(SCROLLWND *sw, HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + RECT hrect; + RECT vrect; + POINT pt; + + pt.x = LOWORD(lParam); + pt.y = HIWORD(lParam); + + //work out exactly where the Horizontal and Vertical scrollbars are + GetHScrollRect(sw, hwnd, &hrect); + GetVScrollRect(sw, hwnd, &vrect); + + //Clicked in the horizontal scrollbar area + if(sw->sbarHorz.fScrollVisible && PtInRect(&hrect, pt)) + { + return HTHSCROLL; + } + //Clicked in the vertical scrollbar area + else if(sw->sbarVert.fScrollVisible && PtInRect(&vrect, pt)) + { + return HTVSCROLL; + } + //clicked somewhere else + else + { + return CallWindowProc(sw->oldproc, hwnd, WM_NCHITTEST, wParam, lParam); + } +} + +// +// Return a HT* value indicating what part of the scrollbar was clicked +// Rectangle is not adjusted +// +static UINT GetHorzPortion(SCROLLBAR *sb, HWND hwnd, RECT *rect, int x, int y) +{ + RECT rc = *rect; + + if(y < rc.top || y >= rc.bottom) return HTSCROLL_NONE; + +#ifdef INCLUDE_BUTTONS + + if(sb->fButVisibleBefore) + { + //clicked on the buttons to the left of the scrollbar + if(x >= rc.left && x < rc.left + sb->nButSizeBefore) + return HTSCROLL_INSERTED; + + //adjust the rectangle to exclude the left-side buttons, now that we + //know we havn't clicked on them + rc.left += sb->nButSizeBefore; + } + + if(sb->fButVisibleAfter) + { + //clicked on the buttons to the right of the scrollbar + if(x >= rc.right - sb->nButSizeAfter && x < rc.right) + return HTSCROLL_INSERTED; + + //adjust the rectangle to exclude the right-side buttons, now that we + //know we havn't clicked on them + rc.right -= sb->nButSizeAfter; + } + +#endif INCLUDE_BUTTONS + + //Now we have the rectangle for the scrollbar itself, so work out + //what part we clicked on. + return GetHorzScrollPortion(sb, hwnd, &rc, x, y); +} + +// +// Just call the horizontal version, with adjusted coordinates +// +static UINT GetVertPortion(SCROLLBAR *sb, HWND hwnd, RECT *rect, int x, int y) +{ + UINT ret; + RotateRect(rect); + ret = GetHorzPortion(sb, hwnd, rect, y, x); + RotateRect(rect); + return ret; +} + +// +// Wrapper function for GetHorzPortion and GetVertPortion +// +static UINT GetPortion(SCROLLBAR *sb, HWND hwnd, RECT *rect, int x, int y) +{ + if(sb->nBarType == SB_HORZ) + return GetHorzPortion(sb, hwnd, rect, x, y); + else if(sb->nBarType == SB_VERT) + return GetVertPortion(sb, hwnd, rect, x, y); + else + return HTSCROLL_NONE; +} + +// +// Input: rectangle of the total scrollbar area +// Output: adjusted to take the inserted buttons into account +// +static void GetRealHorzScrollRect(SCROLLBAR *sb, RECT *rect) +{ + if(sb->fButVisibleBefore) rect->left += sb->nButSizeBefore; + if(sb->fButVisibleAfter) rect->right -= sb->nButSizeAfter; +} + +// +// Input: rectangle of the total scrollbar area +// Output: adjusted to take the inserted buttons into account +// +static void GetRealVertScrollRect(SCROLLBAR *sb, RECT *rect) +{ + if(sb->fButVisibleBefore) rect->top += sb->nButSizeBefore; + if(sb->fButVisibleAfter) rect->bottom -= sb->nButSizeAfter; +} + +// +// Decide which type of scrollbar we have before calling +// the real function to do the job +// +static void GetRealScrollRect(SCROLLBAR *sb, RECT *rect) +{ + if(sb->nBarType == SB_HORZ) + { + GetRealHorzScrollRect(sb, rect); + } + else if(sb->nBarType == SB_VERT) + { + GetRealVertScrollRect(sb, rect); + } +} + +// +// All button code shoule be collected together +// +// +#ifdef INCLUDE_BUTTONS + +// +// Return the index of the button covering the specified point +// rect - rectangle of the whole scrollbar area +// pt - screen coords of the mouse +// fReturnRect - do/don't modify the rect to return the button's area +// +static UINT GetHorzButtonFromPt(SCROLLBAR *sb, RECT *rect, POINT pt, BOOL fReturnRect) +{ + int leftpos = rect->left, rightpos = rect->right; + int i; + int butwidth; + SCROLLBUT *sbut = sb->sbButtons; + + if(!PtInRect(rect, pt)) + return -1; + + if(sb->fButVisibleAfter) + rightpos -= sb->nButSizeAfter; + + for(i = 0; i < sb->nButtons; i++) + { + if(sb->fButVisibleBefore && sbut[i].uPlacement == SBBP_LEFT) + { + butwidth = GetSingleButSize(sb, &sbut[i]); + + //if the current button is under the specified point + if(pt.x >= leftpos && pt.x < leftpos + butwidth) + { + //if the caller wants us to return the rectangle of the button + if(fReturnRect) + { + rect->left = leftpos; + rect->right = leftpos + butwidth; + } + + return i; + } + + leftpos += butwidth; + } + else if(sb->fButVisibleAfter && sbut[i].uPlacement == SBBP_RIGHT) + { + butwidth = GetSingleButSize(sb, &sbut[i]); + + //if the current button is under the specified point + if(pt.x >= rightpos && pt.x < rightpos + butwidth) + { + //if the caller wants us to return the rectangle of the button + if(fReturnRect) + { + rect->left = rightpos; + rect->right = rightpos + butwidth; + } + return i; + } + + rightpos += butwidth; + } + } + + return -1; +} + + +static UINT GetVertButtonFromPt(SCROLLBAR *sb, RECT *rect, POINT pt, BOOL fReturnRect) +{ + UINT ret; + int temp; + + //swap the X/Y coords + temp = pt.x; + pt.x = pt.y; + pt.y = temp; + + //swap the rectangle + RotateRect(rect); + + ret = GetHorzButtonFromPt(sb, rect, pt, fReturnRect); + + RotateRect(rect); + return ret; +} + +// +// +// +static UINT GetButtonFromPt(SCROLLBAR *sb, RECT *rect, POINT pt, BOOL fReturnRect) +{ + if(sb->nBarType == SB_HORZ) + { + return GetHorzButtonFromPt(sb, rect, pt, fReturnRect); + } + else + { + return GetVertButtonFromPt(sb, rect, pt, fReturnRect); + } +} + +// +// Find the coordinates (in RECT format) of the specified button index +// +static UINT GetHorzButtonRectFromId(SCROLLBAR *sb, RECT *rect, UINT index) +{ + UINT i; + SCROLLBUT *sbut = sb->sbButtons; + int leftpos = rect->left, rightpos = rect->right; + + if(sb->fButVisibleAfter) + rightpos -= sb->nButSizeAfter; + + //find the particular button in question + for(i = 0; i < index; i++) + { + if(sb->fButVisibleBefore && sbut[i].uPlacement == SBBP_LEFT) + { + leftpos += GetSingleButSize(sb, &sbut[i]); + } + else if(sb->fButVisibleAfter && sbut[i].uPlacement == SBBP_RIGHT) + { + rightpos += GetSingleButSize(sb, &sbut[i]); + } + } + + //now return the rectangle + if(sbut[i].uPlacement == SBBP_LEFT) + { + rect->left = leftpos; + rect->right = leftpos + GetSingleButSize(sb, &sbut[i]); + } + else + { + rect->left = rightpos; + rect->right = rightpos + GetSingleButSize(sb, &sbut[i]); + } + + return 0; +} + +static UINT GetVertButtonRectFromId(SCROLLBAR *sb, RECT *rect, UINT index) +{ + UINT ret; + RotateRect(rect); + ret = GetHorzButtonRectFromId(sb, rect, index); + RotateRect(rect); + return ret; +} + +static UINT GetButtonRectFromId(SCROLLBAR *sb, RECT *rect, UINT index) +{ + if(sb->nBarType == SB_HORZ) + { + return GetHorzButtonRectFromId(sb, rect, index); + } + else + { + return GetVertButtonRectFromId(sb, rect, index); + } +} +#endif //INCLUDE_BUTTONS + +// +// Left button click in the non-client area +// +static LRESULT NCLButtonDown(SCROLLWND *sw, HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + RECT rect, winrect; + HDC hdc; + SCROLLBAR *sb; + SCROLLBUT *sbut = 0; + POINT pt; + + pt.x = LOWORD(lParam); + pt.y = HIWORD(lParam); + + hwndCurCoolSB = hwnd; + + // + // HORIZONTAL SCROLLBAR PROCESSING + // + if(wParam == HTHSCROLL) + { + uScrollTimerMsg = WM_HSCROLL; + uCurrentScrollbar = SB_HORZ; + sb = &sw->sbarHorz; + + //get the total area of the normal Horz scrollbar area + GetHScrollRect(sw, hwnd, &rect); + uCurrentScrollPortion = GetHorzPortion(sb, hwnd, &rect, LOWORD(lParam), HIWORD(lParam)); + } + // + // VERTICAL SCROLLBAR PROCESSING + // + else if(wParam == HTVSCROLL) + { + uScrollTimerMsg = WM_VSCROLL; + uCurrentScrollbar = SB_VERT; + sb = &sw->sbarVert; + + //get the total area of the normal Horz scrollbar area + GetVScrollRect(sw, hwnd, &rect); + uCurrentScrollPortion = GetVertPortion(sb, hwnd, &rect, LOWORD(lParam), HIWORD(lParam)); + } + // + // NORMAL PROCESSING + // + else + { + uCurrentScrollPortion = HTSCROLL_NONE; + return CallWindowProc(sw->oldproc, hwnd, WM_NCLBUTTONDOWN, wParam, lParam); + } + + // + // we can now share the same code for vertical + // and horizontal scrollbars + // + switch(uCurrentScrollPortion) + { + //inserted buttons to the left/right +#ifdef INCLUDE_BUTTONS + case HTSCROLL_INSERTED: + +#ifdef HOT_TRACKING + KillTimer(hwnd, uMouseOverId); + uMouseOverId = 0; + uMouseOverScrollbar = COOLSB_NONE; +#endif + + //find the index of the button that has been clicked + //adjust the rectangle to give the button's rectangle + uCurrentButton = GetButtonFromPt(sb, &rect, pt, TRUE); + + sbut = &sb->sbButtons[uCurrentButton]; + + //post a notification message + PostMouseNotify(hwnd, NM_CLICK, sb->nBarType, &rect, sbut->uCmdId, pt); + + GetWindowRect(hwnd, &winrect); + OffsetRect(&rect, -winrect.left, -winrect.top); + hdc = GetWindowDC(hwnd); + + DrawScrollButton(sbut, hdc, &rect, SBBS_PUSHED); + + ReleaseDC(hwnd, hdc); + + break; +#endif //INCLUDE_BUTTONS + + case HTSCROLL_THUMB: + + //if the scrollbar is disabled, then do no further processing + if(!IsScrollbarActive(sb)) + return 0; + + GetRealScrollRect(sb, &rect); + RotateRect0(sb, &rect); + CalcThumbSize(sb, &rect, &nThumbSize, &nThumbPos); + RotateRect0(sb, &rect); + + //remember the bounding rectangle of the scrollbar work area + rcThumbBounds = rect; + + sw->fThumbTracking = TRUE; + sb->scrollInfo.nTrackPos = sb->scrollInfo.nPos; + + if(wParam == HTVSCROLL) + nThumbMouseOffset = pt.y - nThumbPos; + else + nThumbMouseOffset = pt.x - nThumbPos; + + nLastPos = -sb->scrollInfo.nPos; + nThumbPos0 = nThumbPos; + + //if(sb->fFlatScrollbar) + //{ + GetWindowRect(hwnd, &winrect); + OffsetRect(&rect, -winrect.left, -winrect.top); + hdc = GetWindowDC(hwnd); + NCDrawScrollbar(sb, hwnd, hdc, &rect, HTSCROLL_THUMB); + ReleaseDC(hwnd, hdc); + //} + + break; + + //Any part of the scrollbar + case HTSCROLL_LEFT: + if(sb->fScrollFlags & ESB_DISABLE_LEFT) return 0; + else goto target1; + + case HTSCROLL_RIGHT: + if(sb->fScrollFlags & ESB_DISABLE_RIGHT) return 0; + else goto target1; + + goto target1; + + case HTSCROLL_PAGELEFT: case HTSCROLL_PAGERIGHT: + + target1: + + //if the scrollbar is disabled, then do no further processing + if(!IsScrollbarActive(sb)) + break; + + //ajust the horizontal rectangle to NOT include + //any inserted buttons + GetRealScrollRect(sb, &rect); + + SendScrollMessage(hwnd, uScrollTimerMsg, uCurrentScrollPortion, 0); + + // Check what area the mouse is now over : + // If the scroll thumb has moved under the mouse in response to + // a call to SetScrollPos etc, then we don't hilight the scrollbar margin + if(uCurrentScrollbar == SB_HORZ) + uScrollTimerPortion = GetHorzScrollPortion(sb, hwnd, &rect, pt.x, pt.y); + else + uScrollTimerPortion = GetVertScrollPortion(sb, hwnd, &rect, pt.x, pt.y); + + GetWindowRect(hwnd, &winrect); + OffsetRect(&rect, -winrect.left, -winrect.top); + hdc = GetWindowDC(hwnd); + +#ifndef HOT_TRACKING + //if we aren't hot-tracking, then don't highlight + //the scrollbar thumb unless we click on it + if(uScrollTimerPortion == HTSCROLL_THUMB) + uScrollTimerPortion = HTSCROLL_NONE; +#endif + NCDrawScrollbar(sb, hwnd, hdc, &rect, uScrollTimerPortion); + ReleaseDC(hwnd, hdc); + + //Post the scroll message!!!! + uScrollTimerPortion = uCurrentScrollPortion; + + //set a timer going on the first click. + //if this one expires, then we can start off a more regular timer + //to generate the auto-scroll behaviour + uScrollTimerId = SetTimer(hwnd, COOLSB_TIMERID1, COOLSB_TIMERINTERVAL1, 0); + break; + default: + return CallWindowProc(sw->oldproc, hwnd, WM_NCLBUTTONDOWN, wParam, lParam); + //return 0; + } + + SetCapture(hwnd); + return 0; +} + +// +// Left button released +// +static LRESULT LButtonUp(SCROLLWND *sw, HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + RECT rect; + //UINT thisportion; + HDC hdc; + POINT pt; + RECT winrect; + UINT buttonIdx = 0; + + //current scrollportion is the button that we clicked down on + if(uCurrentScrollPortion != HTSCROLL_NONE) + { + SCROLLBAR *sb = &sw->sbarHorz; + lParam = GetMessagePos(); + ReleaseCapture(); + + GetWindowRect(hwnd, &winrect); + pt.x = LOWORD(lParam); + pt.y = HIWORD(lParam); + + //emulate the mouse input on a scrollbar here... + if(uCurrentScrollbar == SB_HORZ) + { + //get the total area of the normal Horz scrollbar area + sb = &sw->sbarHorz; + GetHScrollRect(sw, hwnd, &rect); + } + else if(uCurrentScrollbar == SB_VERT) + { + //get the total area of the normal Horz scrollbar area + sb = &sw->sbarVert; + GetVScrollRect(sw, hwnd, &rect); + } + + //we need to do different things depending on if the + //user is activating the scrollbar itself, or one of + //the inserted buttons + switch(uCurrentScrollPortion) + { +#ifdef INCLUDE_BUTTONS + //inserted buttons are being clicked + case HTSCROLL_INSERTED: + + //get the rectangle of the ACTIVE button + buttonIdx = GetButtonFromPt(sb, &rect, pt, FALSE); + GetButtonRectFromId(sb, &rect, uCurrentButton); + + OffsetRect(&rect, -winrect.left, -winrect.top); + + //Send the notification BEFORE we redraw, so the + //bitmap can be changed smoothly by the user if they require + if(uCurrentButton == buttonIdx) + { + SCROLLBUT *sbut = &sb->sbButtons[buttonIdx]; + UINT cmdid = sbut->uCmdId; + + if((sbut->uButType & SBBT_MASK) == SBBT_TOGGLEBUTTON) + sbut->uState ^= 1; + + //send a notify?? + //only post a message if the command id is valid + if(cmdid != -1 && cmdid > 0) + SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(cmdid, CSBN_CLICKED), 0); + + //user might have deleted this button, so redraw whole area + NCPaint(sw, hwnd, 1, 0); + } + else + { + //otherwise, just redraw the button in its new state + hdc = GetWindowDC(hwnd); + DrawScrollButton(&sb->sbButtons[uCurrentButton], hdc, &rect, SBBS_NORMAL); + ReleaseDC(hwnd, hdc); + } + + break; +#endif // INCLUDE_BUTTONS + + //The scrollbar is active + case HTSCROLL_LEFT: case HTSCROLL_RIGHT: + case HTSCROLL_PAGELEFT: case HTSCROLL_PAGERIGHT: + case HTSCROLL_NONE: + + KillTimer(hwnd, uScrollTimerId); + + case HTSCROLL_THUMB: + + //In case we were thumb tracking, make sure we stop NOW + if(sw->fThumbTracking == TRUE) + { + SendScrollMessage(hwnd, uScrollTimerMsg, SB_THUMBPOSITION, nLastPos); + sw->fThumbTracking = FALSE; + } + + //send the SB_ENDSCROLL message now that scrolling has finished + SendScrollMessage(hwnd, uScrollTimerMsg, SB_ENDSCROLL, 0); + + //adjust the total scroll area to become where the scrollbar + //really is (take into account the inserted buttons) + GetRealScrollRect(sb, &rect); + OffsetRect(&rect, -winrect.left, -winrect.top); + hdc = GetWindowDC(hwnd); + + //draw whichever scrollbar sb is + NCDrawScrollbar(sb, hwnd, hdc, &rect, HTSCROLL_NORMAL); + + ReleaseDC(hwnd, hdc); + break; + } + + //reset our state to default + uCurrentScrollPortion = HTSCROLL_NONE; + uScrollTimerPortion = HTSCROLL_NONE; + uScrollTimerId = 0; + + uScrollTimerMsg = 0; + uCurrentScrollbar = COOLSB_NONE; + + return 0; + } + else + { + /* + // Can't remember why I did this! + if(GetCapture() == hwnd) + { + ReleaseCapture(); + }*/ + } + + return CallWindowProc(sw->oldproc, hwnd, WM_LBUTTONUP, wParam, lParam); +} + +// +// This function is called whenever the mouse is moved and +// we are dragging the scrollbar thumb about. +// +static LRESULT ThumbTrackHorz(SCROLLBAR *sbar, HWND hwnd, int x, int y) +{ + POINT pt; + RECT rc, winrect, rc2; + COLORREF crCheck1 = GetSBForeColor(); + COLORREF crCheck2 = GetSBBackColor(); + HDC hdc; + int thumbpos = nThumbPos; + int pos; + int siMaxMin = 0; + UINT flatflag = sbar->fFlatScrollbar ? BF_FLAT : 0; + BOOL fCustomDraw = FALSE; + + SCROLLINFO *si; + si = &sbar->scrollInfo; + + pt.x = x; + pt.y = y; + + //draw the thumb at whatever position + rc = rcThumbBounds; + + SetRect(&rc2, rc.left - THUMBTRACK_SNAPDIST*2, rc.top - THUMBTRACK_SNAPDIST, + rc.right + THUMBTRACK_SNAPDIST*2, rc.bottom + THUMBTRACK_SNAPDIST); + + rc.left += GetScrollMetric(sbar, SM_CXHORZSB); + rc.right -= GetScrollMetric(sbar, SM_CXHORZSB); + + //if the mouse is not in a suitable distance of the scrollbar, + //then "snap" the thumb back to its initial position +#ifdef SNAP_THUMB_BACK + if(!PtInRect(&rc2, pt)) + { + thumbpos = nThumbPos0; + } + //otherwise, move the thumb to where the mouse is + else +#endif //SNAP_THUMB_BACK + { + //keep the thumb within the scrollbar limits + thumbpos = pt.x - nThumbMouseOffset; + if(thumbpos < rc.left) thumbpos = rc.left; + if(thumbpos > rc.right - nThumbSize) thumbpos = rc.right - nThumbSize; + } + + GetWindowRect(hwnd, &winrect); + + if(sbar->nBarType == SB_VERT) + RotateRect(&winrect); + + hdc = GetWindowDC(hwnd); + +//#ifdef CUSTOM_DRAW + fCustomDraw = PostCustomPrePostPaint(hwnd, hdc, sbar, CDDS_PREPAINT) == CDRF_SKIPDEFAULT; +//#endif + + OffsetRect(&rc, -winrect.left, -winrect.top); + thumbpos -= winrect.left; + + //draw the margin before the thumb + SetRect(&rc2, rc.left, rc.top, thumbpos, rc.bottom); + RotateRect0(sbar, &rc2); + + if(fCustomDraw) + PostCustomDrawNotify(hwnd, hdc, sbar->nBarType, &rc2, SB_PAGELEFT, 0, 0, 0); + else + DrawCheckedRect(hdc, &rc2, crCheck1, crCheck2); + + RotateRect0(sbar, &rc2); + + //draw the margin after the thumb + SetRect(&rc2, thumbpos+nThumbSize, rc.top, rc.right, rc.bottom); + + RotateRect0(sbar, &rc2); + + if(fCustomDraw) + PostCustomDrawNotify(hwnd, hdc, sbar->nBarType, &rc2, SB_PAGERIGHT, 0, 0, 0); + else + DrawCheckedRect(hdc, &rc2, crCheck1, crCheck2); + + RotateRect0(sbar, &rc2); + + //finally draw the thumb itelf. This is how it looks on win2000, anyway + SetRect(&rc2, thumbpos, rc.top, thumbpos+nThumbSize, rc.bottom); + + RotateRect0(sbar, &rc2); + + if(fCustomDraw) + PostCustomDrawNotify(hwnd, hdc, sbar->nBarType, &rc2, SB_THUMBTRACK, TRUE, TRUE, FALSE); + else + { + +#ifdef FLAT_SCROLLBARS + if(sbar->fFlatScrollbar) + PaintRect(hdc, &rc2, GetSysColor(COLOR_3DSHADOW)); + else +#endif + { + DrawBlankButton(hdc, &rc2, flatflag); + } + } + + RotateRect0(sbar, &rc2); + ReleaseDC(hwnd, hdc); + + //post a SB_TRACKPOS message!!! + siMaxMin = si->nMax - si->nMin; + + if(siMaxMin > 0) + pos = MulDiv(thumbpos-rc.left, siMaxMin-si->nPage + 1, rc.right-rc.left-nThumbSize); + else + pos = thumbpos - rc.left; + + if(pos != nLastPos) + { + si->nTrackPos = pos; + SendScrollMessage(hwnd, uScrollTimerMsg, SB_THUMBTRACK, pos); + } + + nLastPos = pos; + +//#ifdef CUSTOM_DRAW + PostCustomPrePostPaint(hwnd, hdc, sbar, CDDS_POSTPAINT); +//#endif + + return 0; +} + +// +// remember to rotate the thumb bounds rectangle!! +// +static LRESULT ThumbTrackVert(SCROLLBAR *sb, HWND hwnd, int x, int y) +{ + //sw->swapcoords = TRUE; + RotateRect(&rcThumbBounds); + ThumbTrackHorz(sb, hwnd, y, x); + RotateRect(&rcThumbBounds); + //sw->swapcoords = FALSE; + + return 0; +} + +// +// Called when we have set the capture from the NCLButtonDown(...) +// +static LRESULT MouseMove(SCROLLWND *sw, HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + RECT rect; + UINT thisportion; + HDC hdc; + static UINT lastportion = 0; + static UINT lastbutton = 0; + POINT pt; + RECT winrect; + UINT buttonIdx = 0; + + if(sw->fThumbTracking == TRUE) + { + int x, y; + lParam = GetMessagePos(); + x = LOWORD(lParam); + y = HIWORD(lParam); + + if(uCurrentScrollbar == SB_HORZ) + return ThumbTrackHorz(&sw->sbarHorz, hwnd, x,y); + + + else if(uCurrentScrollbar == SB_VERT) + return ThumbTrackVert(&sw->sbarVert, hwnd, x,y); + } + + if(uCurrentScrollPortion == HTSCROLL_NONE) + { + return CallWindowProc(sw->oldproc, hwnd, WM_MOUSEMOVE, wParam, lParam); + } + else + { + LPARAM nlParam; + SCROLLBAR *sb = &sw->sbarHorz; + SCROLLBUT *sbut = 0; + + nlParam = GetMessagePos(); + + GetWindowRect(hwnd, &winrect); + + pt.x = LOWORD(nlParam); + pt.y = HIWORD(nlParam); + + //emulate the mouse input on a scrollbar here... + if(uCurrentScrollbar == SB_HORZ) + { + sb = &sw->sbarHorz; + } + else if(uCurrentScrollbar == SB_VERT) + { + sb = &sw->sbarVert; + } + + //get the total area of the normal scrollbar area + GetScrollRect(sw, sb->nBarType, hwnd, &rect); + + //see if we clicked in the inserted buttons / normal scrollbar + //thisportion = GetPortion(sb, hwnd, &rect, LOWORD(lParam), HIWORD(lParam)); + thisportion = GetPortion(sb, hwnd, &rect, pt.x, pt.y); + + //we need to do different things depending on if the + //user is activating the scrollbar itself, or one of + //the inserted buttons + switch(uCurrentScrollPortion) + { +#ifdef INCLUDE_BUTTONS + //inserted buttons are being clicked + case HTSCROLL_INSERTED: + + //find the index of the button that has been clicked + //Don't adjust the rectangle though + buttonIdx = GetButtonFromPt(sb, &rect, pt, FALSE); + + //Get the rectangle of the active button + GetButtonRectFromId(sb, &rect, uCurrentButton); + + //if the button to the LEFT of the current + //button is resizable, then resize it +#ifdef RESIZABLE_BUTTONS + if(uCurrentButton > 0) + { + sbut = &sb->sbButtons[uCurrentButton - 1]; + + //only resize if BOTH buttons are on same side of scrollbar + if(sbut->uPlacement == (sbut+1)->uPlacement && (sbut->uButType & SBBM_RESIZABLE)) + { + int oldsize = sbut->nSize; + int butsize1, butsize2; + RECT rect2; + int scrollsize; + + if(uCurrentScrollbar == SB_HORZ) + { + rect.left -= GetSingleButSize(sb, sbut); + sbut->nSize = pt.x - rect.left; + } + else + { + rect.top -= GetSingleButSize(sb, sbut); + sbut->nSize = pt.y - rect.top; + } + + //if(sbut->nSize < 0) sbut->nSize = 0; + if(sbut->nSize < (int)sbut->nMinSize) + sbut->nSize = sbut->nMinSize; + + if((UINT)sbut->nSize > (UINT)sbut->nMaxSize) + sbut->nSize = sbut->nMaxSize; + + GetScrollRect(sw, uCurrentScrollbar, hwnd, &rect2); + + if(uCurrentScrollbar == SB_HORZ) + scrollsize = rect2.right-rect2.left; + else + scrollsize = rect2.bottom-rect2.top; + + butsize1 = GetButtonSize(sb, hwnd, SBBP_LEFT); + butsize2 = GetButtonSize(sb, hwnd, SBBP_RIGHT); + + //adjust the button size if it gets too big + if(butsize1 + butsize2 > scrollsize - MINSCROLLSIZE) + { + sbut->nSize -= (butsize1+butsize2) - (scrollsize - MINSCROLLSIZE); + } + + //remember what size the USER set the button to + sbut->nSizeReserved = sbut->nSize; + NCPaint(sw, hwnd, (WPARAM)1, (LPARAM)0); + return 0; + } + } +#endif //RESIZABLE_BUTTONS + + OffsetRect(&rect, -winrect.left, -winrect.top); + + hdc = GetWindowDC(hwnd); + + //if the button under the mouse is not the active button, + //then display the active button in its normal state + if(buttonIdx != uCurrentButton + //include this if toggle buttons always stay depressed + //if they are being activated + && (sb->sbButtons[uCurrentButton].uButType & SBBT_MASK) != SBBT_TOGGLEBUTTON) + { + if(lastbutton != buttonIdx) + DrawScrollButton(&sb->sbButtons[uCurrentButton], hdc, &rect, SBBS_NORMAL); + } + //otherwise, depress the active button if the mouse is over + //it (just like a normal scroll button works) + else + { + if(lastbutton != buttonIdx) + DrawScrollButton(&sb->sbButtons[uCurrentButton], hdc, &rect, SBBS_PUSHED); + } + + ReleaseDC(hwnd, hdc); + return CallWindowProc(sw->oldproc, hwnd, WM_MOUSEMOVE, wParam, lParam); + //break; + +#endif //INCLUDE_BUTTONS + + //The scrollbar is active + case HTSCROLL_LEFT: case HTSCROLL_RIGHT:case HTSCROLL_THUMB: + case HTSCROLL_PAGELEFT: case HTSCROLL_PAGERIGHT: + case HTSCROLL_NONE: + + //adjust the total scroll area to become where the scrollbar + //really is (take into account the inserted buttons) + GetRealScrollRect(sb, &rect); + + OffsetRect(&rect, -winrect.left, -winrect.top); + hdc = GetWindowDC(hwnd); + + if(thisportion != uCurrentScrollPortion) + { + uScrollTimerPortion = HTSCROLL_NONE; + + if(lastportion != thisportion) + NCDrawScrollbar(sb, hwnd, hdc, &rect, HTSCROLL_NORMAL); + } + //otherwise, draw the button in its depressed / clicked state + else + { + uScrollTimerPortion = uCurrentScrollPortion; + + if(lastportion != thisportion) + NCDrawScrollbar(sb, hwnd, hdc, &rect, thisportion); + } + + ReleaseDC(hwnd, hdc); + + break; + } + + + lastportion = thisportion; + lastbutton = buttonIdx; + + //must return zero here, because we might get cursor anomilies + //CallWindowProc(sw->oldproc, hwnd, WM_MOUSEMOVE, wParam, lParam); + return 0; + + } +} + +#ifdef INCLUDE_BUTTONS +#ifdef RESIZABLE_BUTTONS +// +// Any resizable buttons must be shrunk to fit if the window is made too small +// +static void ResizeButtonsToFit(SCROLLWND *sw, SCROLLBAR *sbar, HWND hwnd) +{ + int butsize1, butsize2; + RECT rc; + int scrollsize; + int i; + SCROLLBUT *sbut; + + //make sure that the scrollbar can fit into space, by + //shrinking any resizable buttons + GetScrollRect(sw, sbar->nBarType, hwnd, &rc); + + if(sbar->nBarType == SB_HORZ) + scrollsize = rc.right-rc.left; + else + scrollsize = rc.bottom-rc.top; + + //restore any resizable buttons to their user-defined sizes, + //before shrinking them to fit. This means when we make the window + //bigger, the buttons will restore to their initial sizes + for(i = 0; i < sbar->nButtons; i++) + { + sbut = &sbar->sbButtons[i]; + if(sbut->uButType & SBBM_RESIZABLE) + { + sbut->nSize = sbut->nSizeReserved; + } + } + + butsize1 = GetButtonSize(sbar, hwnd, SBBP_LEFT); + butsize2 = GetButtonSize(sbar, hwnd, SBBP_RIGHT); + + if(butsize1 + butsize2 > scrollsize - MINSCROLLSIZE) + { + i = 0; + while(i < sbar->nButtons && + butsize1 + butsize2 > scrollsize - MINSCROLLSIZE) + { + sbut = &sbar->sbButtons[i++]; + if(sbut->uButType & SBBM_RESIZABLE) + { + int oldsize = sbut->nSize; + sbut->nSize -= (butsize1+butsize2) - (scrollsize-MINSCROLLSIZE); + + if(sbut->nSize < (int)sbut->nMinSize) + sbut->nSize = sbut->nMinSize; + + if((UINT)sbut->nSize > (UINT)sbut->nMaxSize) + sbut->nSize = sbut->nMaxSize; + + + butsize1 -= (oldsize - sbut->nSize); + } + } + } + +} +#endif +#endif + +// +// We must allocate from in the non-client area for our scrollbars +// Call the default window procedure first, to get the borders (if any) +// allocated some space, then allocate the space for the scrollbars +// if they fit +// +static LRESULT NCCalcSize(SCROLLWND *sw, HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + NCCALCSIZE_PARAMS *nccsp; + RECT *rect; + RECT oldrect; + BOOL fCalcValidRects = (wParam == TRUE); + SCROLLBAR *sb; + LRESULT ret; + DWORD dwStyle; + + //Regardless of the value of fCalcValidRects, the first rectangle + //in the array specified by the rgrc structure member of the + //NCCALCSIZE_PARAMS structure contains the coordinates of the window, + //so we can use the exact same code to modify this rectangle, when + //wParam is TRUE and when it is FALSE. + nccsp = (NCCALCSIZE_PARAMS *)lParam; + rect = &nccsp->rgrc[0]; + oldrect = *rect; + + dwStyle = GetWindowLong(hwnd, GWL_STYLE); + + // TURN OFF SCROLL-STYLES. + if ( dwStyle & (WS_VSCROLL|WS_HSCROLL) ) + { + sw->bPreventStyleChange = TRUE; + SetWindowLong(hwnd, GWL_STYLE, dwStyle & ~(WS_VSCROLL|WS_HSCROLL)); + } + + //call the default procedure to get the borders allocated + ret = CallWindowProc(sw->oldproc, hwnd, WM_NCCALCSIZE, wParam, lParam); + + // RESTORE PREVIOUS STYLES (if present at all) + if ( dwStyle & (WS_VSCROLL|WS_HSCROLL) ) + { + SetWindowLong(hwnd, GWL_STYLE, dwStyle); + sw->bPreventStyleChange = FALSE; + } + + // calculate what the size of each window border is, + sw->cxLeftEdge = rect->left - oldrect.left; + sw->cxRightEdge = oldrect.right - rect->right; + sw->cyTopEdge = rect->top - oldrect.top; + sw->cyBottomEdge = oldrect.bottom - rect->bottom; + + sb = &sw->sbarHorz; + + //if there is room, allocate some space for the horizontal scrollbar + //NOTE: Change the ">" to a ">=" to make the horz bar totally fill the + //window before disappearing + if((sb->fScrollFlags & CSBS_VISIBLE) && +#ifdef COOLSB_FILLWINDOW + rect->bottom - rect->top >= GetScrollMetric(sb, SM_CYHORZSB)) +#else + rect->bottom - rect->top > GetScrollMetric(sb, SM_CYHORZSB)) +#endif + { + rect->bottom -= GetScrollMetric(sb, SM_CYHORZSB); + sb->fScrollVisible = TRUE; + } + else + sb->fScrollVisible = FALSE; + + sb = &sw->sbarVert; + + //if there is room, allocate some space for the vertical scrollbar + if((sb->fScrollFlags & CSBS_VISIBLE) && + rect->right - rect->left >= GetScrollMetric(sb, SM_CXVERTSB)) + { + if(sw->fLeftScrollbar) + rect->left += GetScrollMetric(sb, SM_CXVERTSB); + else + rect->right -= GetScrollMetric(sb, SM_CXVERTSB); + + sb->fScrollVisible = TRUE; + } + else + sb->fScrollVisible = FALSE; + +#ifdef INCLUDE_BUTTONS +#ifdef RESIZABLE_BUTTONS + ResizeButtonsToFit(sw, &sw->sbarHorz, hwnd); + ResizeButtonsToFit(sw, &sw->sbarVert, hwnd); +#endif +#endif + + //don't return a value unless we actually modify the other rectangles + //in the NCCALCSIZE_PARAMS structure. In this case, we return 0 + //no matter what the value of fCalcValidRects is + return ret;//FALSE; +} + +// +// used for hot-tracking over the scroll buttons +// +static LRESULT NCMouseMove(SCROLLWND *sw, HWND hwnd, WPARAM wHitTest, LPARAM lParam) +{ + //install a timer for the mouse-over events, if the mouse moves + //over one of the scrollbars +#ifdef HOT_TRACKING + hwndCurCoolSB = hwnd; + if(wHitTest == HTHSCROLL) + { + if(uMouseOverScrollbar == SB_HORZ) + return CallWindowProc(sw->oldproc, hwnd, WM_NCMOUSEMOVE, wHitTest, lParam); + + uLastHitTestPortion = HTSCROLL_NONE; + uHitTestPortion = HTSCROLL_NONE; + GetScrollRect(sw, SB_HORZ, hwnd, &MouseOverRect); + uMouseOverScrollbar = SB_HORZ; + uMouseOverId = SetTimer(hwnd, COOLSB_TIMERID3, COOLSB_TIMERINTERVAL3, 0); + + NCPaint(sw, hwnd, 1, 0); + } + else if(wHitTest == HTVSCROLL) + { + if(uMouseOverScrollbar == SB_VERT) + return CallWindowProc(sw->oldproc, hwnd, WM_NCMOUSEMOVE, wHitTest, lParam); + + uLastHitTestPortion = HTSCROLL_NONE; + uHitTestPortion = HTSCROLL_NONE; + GetScrollRect(sw, SB_VERT, hwnd, &MouseOverRect); + uMouseOverScrollbar = SB_VERT; + uMouseOverId = SetTimer(hwnd, COOLSB_TIMERID3, COOLSB_TIMERINTERVAL3, 0); + + NCPaint(sw, hwnd, 1, 0); + } + +#endif //HOT_TRACKING + return CallWindowProc(sw->oldproc, hwnd, WM_NCMOUSEMOVE, wHitTest, lParam); +} + +// +// Timer routine to generate scrollbar messages +// +static LRESULT CoolSB_Timer(SCROLLWND *swnd, HWND hwnd, WPARAM wTimerId, LPARAM lParam) +{ + //let all timer messages go past if we don't have a timer installed ourselves + if(uScrollTimerId == 0 && uMouseOverId == 0) + { + return CallWindowProc(swnd->oldproc, hwnd, WM_TIMER, wTimerId, lParam); + } + +#ifdef HOT_TRACKING + //mouse-over timer + if(wTimerId == COOLSB_TIMERID3) + { + POINT pt; + RECT rect, winrect; + HDC hdc; + SCROLLBAR *sbar; + + if(swnd->fThumbTracking) + return 0; + + //if the mouse moves outside the current scrollbar, + //then kill the timer.. + GetCursorPos(&pt); + + if(!PtInRect(&MouseOverRect, pt)) + { + KillTimer(hwnd, uMouseOverId); + uMouseOverId = 0; + uMouseOverScrollbar = COOLSB_NONE; + uLastHitTestPortion = HTSCROLL_NONE; + + uHitTestPortion = HTSCROLL_NONE; + NCPaint(swnd, hwnd, 1, 0); + } + else + { + if(uMouseOverScrollbar == SB_HORZ) + { + sbar = &swnd->sbarHorz; + uHitTestPortion = GetHorzPortion(sbar, hwnd, &MouseOverRect, pt.x, pt.y); + } + else + { + sbar = &swnd->sbarVert; + uHitTestPortion = GetVertPortion(sbar, hwnd, &MouseOverRect, pt.x, pt.y); + } + + if(uLastHitTestPortion != uHitTestPortion) + { + rect = MouseOverRect; + GetRealScrollRect(sbar, &rect); + + GetWindowRect(hwnd, &winrect); + OffsetRect(&rect, -winrect.left, -winrect.top); + + hdc = GetWindowDC(hwnd); + NCDrawScrollbar(sbar, hwnd, hdc, &rect, HTSCROLL_NONE); + ReleaseDC(hwnd, hdc); + } + + uLastHitTestPortion = uHitTestPortion; + } + + return 0; + } +#endif // HOT_TRACKING + + //if the first timer goes off, then we can start a more + //regular timer interval to auto-generate scroll messages + //this gives a slight pause between first pressing the scroll arrow, and the + //actual scroll starting + if(wTimerId == COOLSB_TIMERID1) + { + KillTimer(hwnd, uScrollTimerId); + uScrollTimerId = SetTimer(hwnd, COOLSB_TIMERID2, COOLSB_TIMERINTERVAL2, 0); + return 0; + } + //send the scrollbar message repeatedly + else if(wTimerId == COOLSB_TIMERID2) + { + //need to process a spoof WM_MOUSEMOVE, so that + //we know where the mouse is each time the scroll timer goes off. + //This is so we can stop sending scroll messages if the thumb moves + //under the mouse. + POINT pt; + GetCursorPos(&pt); + ScreenToClient(hwnd, &pt); + + MouseMove(swnd, hwnd, MK_LBUTTON, MAKELPARAM(pt.x, pt.y)); + + if(uScrollTimerPortion != HTSCROLL_NONE) + SendScrollMessage(hwnd, uScrollTimerMsg, uScrollTimerPortion, 0); + + return 0; + } + else + { + return CallWindowProc(swnd->oldproc, hwnd, WM_TIMER, wTimerId, lParam); + } +} + +// +// We must intercept any calls to SetWindowLong, to check if +// left-scrollbars are taking effect or not +// +static LRESULT CoolSB_StyleChange(SCROLLWND *swnd, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + STYLESTRUCT *ss = (STYLESTRUCT *)lParam; + + if(wParam == GWL_EXSTYLE) + { + if(ss->styleNew & WS_EX_LEFTSCROLLBAR) + swnd->fLeftScrollbar = TRUE; + else + swnd->fLeftScrollbar = FALSE; + } + + return CallWindowProc(swnd->oldproc, hwnd, msg, wParam, lParam); +} + +static UINT curTool = -1; +static LRESULT CoolSB_Notify(SCROLLWND *swnd, HWND hwnd, WPARAM wParam, LPARAM lParam) +{ +#ifdef COOLSB_TOOLTIPS + + NMTTDISPINFO *nmdi = (NMTTDISPINFO *)lParam; + + if(nmdi->hdr.hwndFrom == swnd->hwndToolTip && + nmdi->hdr.code == TTN_GETDISPINFO) + { + //convert the tooltip notify from a "ISHWND" style + //request to an id-based request. + //We do this because our tooltip is a window-style + //tip, with no tools, and the GETDISPINFO request must + //indicate which button to retrieve the text for + //nmdi->hdr.idFrom = curTool; + nmdi->hdr.idFrom = curTool; + nmdi->hinst = GetModuleHandle(0); + nmdi->uFlags &= ~TTF_IDISHWND; + } +#endif //COOLSB_TOOLTIPS + + return CallWindowProc(swnd->oldproc, hwnd, WM_NOTIFY, wParam, lParam); +} + +static LRESULT SendToolTipMessage0(HWND hwndTT, UINT message, WPARAM wParam, LPARAM lParam) +{ + return SendMessage(hwndTT, message, wParam, lParam); +} + +#ifdef COOLSB_TOOLTIPS +#define SendToolTipMessage SendToolTipMessage0 +#else +#define SendToolTipMessage 1 ? (void)0 : SendToolTipMessage0 +#endif + + +// +// We must intercept any calls to SetWindowLong, to make sure that +// the user does not set the WS_VSCROLL or WS_HSCROLL styles +// +static LRESULT CoolSB_SetCursor(SCROLLWND *swnd, HWND hwnd, WPARAM wParam, LPARAM lParam) +{ +#ifdef INCLUDE_BUTTONS + UINT lo = LOWORD(lParam); + UINT hi = HIWORD(lParam); + UINT xy; + RECT rect; + SCROLLBAR *sbar; + SCROLLBUT *sbut; + POINT pt; + UINT id; + static UINT lastid; + +#ifdef HIDE_CURSOR_AFTER_MOUSEUP + static UINT lastmsg; + if(lastmsg == WM_LBUTTONDOWN) + { + lastmsg = hi; + return CallWindowProc(swnd->oldproc, hwnd, WM_SETCURSOR, wParam, lParam); + } + else + lastmsg = hi; +#endif + + //if we are over either or our scrollbars + if(lo == HTHSCROLL || lo == HTVSCROLL) + { + xy = GetMessagePos(); + pt.x = LOWORD(xy); + pt.y = HIWORD(xy); + + if(lo == HTHSCROLL) + { + sbar = &swnd->sbarHorz; + GetScrollRect(swnd, SB_HORZ, hwnd, &rect); + id = GetHorzPortion(sbar, hwnd, &rect, pt.x, pt.y); + } + else + { + sbar = &swnd->sbarVert; + GetScrollRect(swnd, SB_VERT, hwnd, &rect); + id = GetVertPortion(sbar, hwnd, &rect, pt.x, pt.y); + } + + if(id != HTSCROLL_INSERTED) + { + if(swnd->hwndToolTip != 0) + { + SendToolTipMessage(swnd->hwndToolTip, TTM_ACTIVATE, FALSE, 0); + SendToolTipMessage(swnd->hwndToolTip, TTM_POP, 0, 0); + } + + return CallWindowProc(swnd->oldproc, hwnd, WM_SETCURSOR, wParam, lParam); + } + + if(swnd->hwndToolTip != 0) + { + SendToolTipMessage(swnd->hwndToolTip, TTM_ACTIVATE, TRUE, 0); + } + + //set the cursor if one has been specified + if((id = GetButtonFromPt(sbar, &rect, pt, TRUE)) != -1) + { + sbut = &sbar->sbButtons[id]; + curTool = sbut->uCmdId; + + if(lastid != id && swnd->hwndToolTip != 0) + { + if(IsWindowVisible(swnd->hwndToolTip)) + SendToolTipMessage(swnd->hwndToolTip, TTM_UPDATE, TRUE, 0); + } + + lastid = id; + + if(sbut->hCurs != 0) + { + SetCursor(sbut->hCurs); + return 0; + } + } + else + { + curTool = -1; + lastid = -1; + } + } + else if(swnd->hwndToolTip != 0) + { + SendToolTipMessage(swnd->hwndToolTip, TTM_ACTIVATE, FALSE, 0); + SendToolTipMessage(swnd->hwndToolTip, TTM_POP, 0, 0); + } + +#endif //INCLUDE_BUTTONS + return CallWindowProc(swnd->oldproc, hwnd, WM_SETCURSOR, wParam, lParam); +} + + +// +// Send the specified message to the tooltip control +// +static void __stdcall RelayMouseEvent(HWND hwnd, HWND hwndToolTip, UINT event) +{ +#ifdef COOLSB_TOOLTIPS + MSG msg; + + CoolSB_ZeroMemory(&msg, sizeof(MSG)); + msg.hwnd = hwnd; + msg.message = event; + + SendMessage(hwndToolTip, TTM_RELAYEVENT, 0, (LONG)&msg); +#else + UNREFERENCED_PARAMETER(hwnd); + UNREFERENCED_PARAMETER(hwndToolTip); + UNREFERENCED_PARAMETER(event); +#endif +} + + +// +// CoolScrollbar subclass procedure. +// Handle all messages needed to mimick normal windows scrollbars +// +LRESULT CALLBACK CoolSBWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + WNDPROC oldproc; + SCROLLWND *swnd = GetScrollWndFromHwnd(hwnd); + static int count; + + switch(message) + { + case WM_NCDESTROY: + //this should NEVER be called, because the user + //should have called Uninitialize() themselves. + + //However, if the user tries to call Uninitialize().. + //after this window is destroyed, this window's entry in the lookup + //table will not be there, and the call will fail + oldproc = swnd->oldproc; + UninitializeCoolSB(hwnd); + + //we must call the original window procedure, otherwise it + //will never get the WM_NCDESTROY message, and it wouldn't + //be able to clean up etc. + return CallWindowProc(oldproc, hwnd, message, wParam, lParam); + + case WM_NCCALCSIZE: + return NCCalcSize(swnd, hwnd, wParam, lParam); + + case WM_NCPAINT: + return NCPaint(swnd, hwnd, wParam, lParam); + + case WM_NCHITTEST: + return NCHitTest(swnd, hwnd, wParam, lParam); + + case WM_NCRBUTTONDOWN: case WM_NCRBUTTONUP: + case WM_NCMBUTTONDOWN: case WM_NCMBUTTONUP: + RelayMouseEvent(hwnd, swnd->hwndToolTip, (WM_MOUSEMOVE-WM_NCMOUSEMOVE) + (message)); + if(wParam == HTHSCROLL || wParam == HTVSCROLL) + return 0; + else + break; + + case WM_NCLBUTTONDBLCLK: + //TRACE("WM_NCLBUTTONDBLCLK %d\n", count++); + if(wParam == HTHSCROLL || wParam == HTVSCROLL) + return NCLButtonDown(swnd, hwnd, wParam, lParam); + else + break; + + case WM_NCLBUTTONDOWN: + //TRACE("WM_NCLBUTTONDOWN%d\n", count++); + RelayMouseEvent(hwnd, swnd->hwndToolTip, WM_LBUTTONDOWN); + return NCLButtonDown(swnd, hwnd, wParam, lParam); + + + case WM_LBUTTONUP: + //TRACE("WM_LBUTTONUP %d\n", count++); + RelayMouseEvent(hwnd, swnd->hwndToolTip, WM_LBUTTONUP); + return LButtonUp(swnd, hwnd, wParam, lParam); + + case WM_NOTIFY: + return CoolSB_Notify(swnd, hwnd, wParam, lParam); + + //Mouse moves are received when we set the mouse capture, + //even when the mouse moves over the non-client area + case WM_MOUSEMOVE: + //TRACE("WM_MOUSEMOVE %d\n", count++); + return MouseMove(swnd, hwnd, wParam, lParam); + + case WM_TIMER: + return CoolSB_Timer(swnd, hwnd, wParam, lParam); + + //case WM_STYLECHANGING: + // return CoolSB_StyleChange(swnd, hwnd, WM_STYLECHANGING, wParam, lParam); + case WM_STYLECHANGED: + + if(swnd->bPreventStyleChange) + { + // the NCPAINT handler has told us to eat this message! + return 0; + } + else + { + if (message == WM_STYLECHANGED) + return CoolSB_StyleChange(swnd, hwnd, WM_STYLECHANGED, wParam, lParam); + else + break; + } + + case WM_NCMOUSEMOVE: + { + static LONG_PTR lastpos = -1; + + //TRACE("WM_NCMOUSEMOVE %d\n", count++); + + //The problem with NCMOUSEMOVE is that it is sent continuously + //even when the mouse is stationary (under win2000 / win98) + // + //Tooltips don't like being sent a continous stream of mouse-moves + //if the cursor isn't moving, because they will think that the mouse + //is moving position, and the internal timer will never expire + // + if(lastpos != lParam) + { + RelayMouseEvent(hwnd, swnd->hwndToolTip, WM_MOUSEMOVE); + lastpos = lParam; + } + } + + return NCMouseMove(swnd, hwnd, wParam, lParam); + + + case WM_SETCURSOR: + return CoolSB_SetCursor(swnd, hwnd, wParam, lParam); + + case WM_CAPTURECHANGED: + break; + + default: + break; + } + + return CallWindowProc(swnd->oldproc, hwnd, message, wParam, lParam); +} + diff --git a/plugins/Clist_nicer/coolsb/coolscroll.h b/plugins/Clist_nicer/coolsb/coolscroll.h new file mode 100644 index 0000000000..c5fe848a83 --- /dev/null +++ b/plugins/Clist_nicer/coolsb/coolscroll.h @@ -0,0 +1,232 @@ +#ifndef _COOLSBLIB_INCLUDED +#define _COOLSBLIB_INCLUDED + +#ifdef __cplusplus +extern "C"{ +#endif + +#include +#include + +// To complement the exisiting SB_HORZ, SB_VERT, SB_BOTH +// scrollbar identifiers +#define COOLSB_NONE (-1) +#define SB_INSBUT (-2) + +// +// Arrow size defines +// +#define SYSTEM_METRIC (-1) + + +// +// general scrollbar styles +// +// use the standard ESB_DISABLE_xxx flags to represent the +// enabled / disabled states. (defined in winuser.h) +// +#define CSBS_THUMBALWAYS 4 +#define CSBS_VISIBLE 8 + +//cool scrollbar styles for Flat scrollbars +#define CSBS_NORMAL 0 +#define CSBS_FLAT 1 +#define CSBS_HOTTRACKED 2 + +// +// Button mask flags for indicating which members of SCROLLBUT +// to use during a button insertion / modification +// +#define SBBF_TYPE 0x0001 +#define SBBF_ID 0x0002 +#define SBBF_PLACEMENT 0x0004 +#define SBBF_SIZE 0x0008 +#define SBBF_BITMAP 0x0010 +#define SBBF_ENHMETAFILE 0x0020 +//#define SBBF_OWNERDRAW 0x0040 //unused at present +#define SBBF_CURSOR 0x0080 +#define SBBF_BUTMINMAX 0x0100 +#define SBBF_STATE 0x0200 + +//button styles (states) +#define SBBS_NORMAL 0 +#define SBBS_PUSHED 1 +#define SBBS_CHECKED SBBS_PUSHED + +// +// scrollbar button types +// +#define SBBT_PUSHBUTTON 1 //standard push button +#define SBBT_TOGGLEBUTTON 2 //toggle button +#define SBBT_FIXED 3 //fixed button (non-clickable) +#define SBBT_FLAT 4 //blank area (flat, with border) +#define SBBT_BLANK 5 //blank area (flat, no border) +#define SBBT_DARK 6 //dark blank area (flat) +#define SBBT_OWNERDRAW 7 //user draws the button via a WM_NOTIFY + +#define SBBT_MASK 0x1f //mask off low 5 bits + +//button type modifiers +#define SBBM_RECESSED 0x0020 //recessed when clicked (like Word 97) +#define SBBM_LEFTARROW 0x0040 +#define SBBM_RIGHTARROW 0x0080 +#define SBBM_UPARROW 0x0100 +#define SBBM_DOWNARROW 0x0200 +#define SBBM_RESIZABLE 0x0400 +#define SBBM_TYPE2 0x0800 +#define SBBM_TYPE3 0x1000 +#define SBBM_TOOLTIPS 0x2000 //currently unused (define COOLSB_TOOLTIPS in userdefs.h) + +//button placement flags +#define SBBP_LEFT 1 +#define SBBP_RIGHT 2 +#define SBBP_TOP 1 //3 +#define SBBP_BOTTOM 2 //4 + + +// +// Button command notification codes +// for sending with a WM_COMMAND message +// +#define CSBN_BASE 0 +#define CSBN_CLICKED (1 + CSBN_BASE) +#define CSBN_HILIGHT (2 + CSBN_BASE) + +// +// Minimum size in pixels of a scrollbar thumb +// +#define MINTHUMBSIZE_NT4 8 +#define MINTHUMBSIZE_2000 6 + +//define some more hittest values for our cool-scrollbar +#define HTSCROLL_LEFT (SB_LINELEFT) +#define HTSCROLL_RIGHT (SB_LINERIGHT) +#define HTSCROLL_UP (SB_LINEUP) +#define HTSCROLL_DOWN (SB_LINEDOWN) +#define HTSCROLL_THUMB (SB_THUMBTRACK) +#define HTSCROLL_PAGEGUP (SB_PAGEUP) +#define HTSCROLL_PAGEGDOWN (SB_PAGEDOWN) +#define HTSCROLL_PAGELEFT (SB_PAGELEFT) +#define HTSCROLL_PAGERIGHT (SB_PAGERIGHT) + +#define HTSCROLL_NONE (-1) +#define HTSCROLL_NORMAL (-1) + +#define HTSCROLL_INSERTED (128) +#define HTSCROLL_PRE (32 | HTSCROLL_INSERTED) +#define HTSCROLL_POST (64 | HTSCROLL_INSERTED) + +/* + + Public interface to the Cool Scrollbar library + + +*/ + +BOOL WINAPI InitializeCoolSB(HWND hwnd); +HRESULT WINAPI UninitializeCoolSB (HWND hwnd); + +BOOL WINAPI CoolSB_SetMinThumbSize(HWND hwnd, UINT wBar, UINT size); +BOOL WINAPI CoolSB_IsThumbTracking(HWND hwnd); +BOOL WINAPI CoolSB_IsCoolScrollEnabled(HWND hwnd); + +// +BOOL WINAPI CoolSB_EnableScrollBar (HWND hwnd, int wSBflags, UINT wArrows); +BOOL WINAPI CoolSB_GetScrollInfo (HWND hwnd, int fnBar, LPSCROLLINFO lpsi); +int WINAPI CoolSB_GetScrollPos (HWND hwnd, int nBar); +BOOL WINAPI CoolSB_GetScrollRange (HWND hwnd, int nBar, LPINT lpMinPos, LPINT lpMaxPos); + +// +int WINAPI CoolSB_SetScrollInfo (HWND hwnd, int fnBar, LPSCROLLINFO lpsi, BOOL fRedraw); +int WINAPI CoolSB_SetScrollPos (HWND hwnd, int nBar, int nPos, BOOL fRedraw); +int WINAPI CoolSB_SetScrollRange (HWND hwnd, int nBar, int nMinPos, int nMaxPos, BOOL fRedraw); +BOOL WINAPI CoolSB_ShowScrollBar (HWND hwnd, int wBar, BOOL fShow); + +// +// Scrollbar dimension functions +// +BOOL WINAPI CoolSB_SetSize (HWND hwnd, int wBar, int nLength, int nWidth); + +// +// Set the visual nature of a scrollbar (flat, normal etc) +// +BOOL WINAPI CoolSB_SetStyle (HWND hwnd, int wBar, UINT nStyle); +BOOL WINAPI CoolSB_SetThumbAlways (HWND hwnd, int wBar, BOOL fThumbAlways); + +// +// Scrollbar button structure, for inserted buttons only +// +typedef struct +{ + UINT fMask; //which members are in use + UINT uPlacement; //is this button to the left/right (above/below) of the scrollbar?? + UINT uCmdId; //command identifier (WM_COMMAND value to send) + UINT uButType; // + UINT uState; //toggled etc + int nSize; //size in pixels. -1 for autosize + + HBITMAP hBmp; //handle to a bitmap to use as the button face + HENHMETAFILE hEmf; //handle to an enhanced metafile + + HCURSOR hCurs; //handle to a user-supplied mouse cursor to apply + //to this button + + int nSizeReserved; //internal variable used for resizing + int nMinSize; //min size + int nMaxSize; //max size + +} SCROLLBUT; + +BOOL WINAPI CoolSB_InsertButton(HWND hwnd, int wSBflags, UINT nPos, SCROLLBUT *psb); +BOOL WINAPI CoolSB_ModifyButton(HWND hwnd, int wSBflags, UINT uItem, BOOL fByCmd, SCROLLBUT *psb); +BOOL WINAPI CoolSB_RemoveButton(HWND hwnd, int wSBflags, UINT uItem, BOOL fByCmd); +BOOL WINAPI CoolSB_GetButton (HWND hwnd, int wSBflags, UINT uItem, BOOL fByCmd, SCROLLBUT *psb); + +void WINAPI CoolSB_SetESBProc(void *proc); + +typedef struct +{ + NMHDR hdr; + DWORD dwDrawStage; + HDC hdc; + RECT rect; + UINT uItem; + UINT uState; + UINT nBar; + +} NMCSBCUSTOMDRAW; + +typedef struct +{ + NMHDR hdr; + RECT rect; + POINT pt; + UINT uCmdId; + UINT uState; + int nBar; +} NMCOOLBUTMSG; + +/* +typedef struct +{ + NMHDR hdr; + DWORD dwDrawStage; + HDC hdc; + RECT rect; + UINT uCmdId; + UINT uState; + +} NMCOOLBUTTON_CUSTOMDRAW; +*/ + + +// +// Define the WM_NOTIFY code value for cool-scrollbar custom drawing +// +#define NM_COOLSB_CUSTOMDRAW (0-0xfffU) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/plugins/Clist_nicer/coolsb/userdefs.h b/plugins/Clist_nicer/coolsb/userdefs.h new file mode 100644 index 0000000000..ea7ea1fe92 --- /dev/null +++ b/plugins/Clist_nicer/coolsb/userdefs.h @@ -0,0 +1,79 @@ +#ifndef _USERDEFINES_INCLUDED +#define _USERDEFINES_INCLUDED + +/* + + Define these values to alter the various + features of the coolscroll library. If you don't want + a certain feature, then you might be able to reduce the + size of your app by a few kb... + +*/ + +/* allow inserted buttons. Without this, all button code will + be excluded, resulting in a smaller build (about 4kb less). This + may not seem much, but it is a 25% reduction! */ +//#define INCLUDE_BUTTONS + +/* Allow user-resizable buttons. Makes no difference if INCLUDE_BUTTONS + is not defined for the project */ +#define RESIZABLE_BUTTONS + +/* Include tooltip support for inserted buttons. Without this, no + tooltip requests (TTN_GETDISPINFO's) will be sent to the window */ +//#define COOLSB_TOOLTIPS + +/* Define this to include the custom-draw support */ +#define CUSTOM_DRAW + +/* Define to enable WM_NOTIFY messages to be sent for mouse event */ +#define NOTIFY_MOUSE + +/* Define this value to make the horizontal scrollbar stay visible even + if the window is sized to small vertically. Normal scrollbars always leave + a 1-pixel line of "client" area before hiding the horizontal scrollbar. This + value allows the window to be sized so the client area totally disappears if + sized too small */ +//#define COOLSB_FILLWINDOW + +/* minimum size of scrollbar before inserted buttons are + hidden to make room when the window is sized too small */ +#define MIN_COOLSB_SIZE 24 + +/* min size of scrollbar when resizing a button, before the + resize is stopped because the scrollbar has gotten too small */ +#define MINSCROLLSIZE 50 + +/* define this to display the default mouse arrow whenever the + the mouse is released over a button which has a user-defined cursor. + not really very useful, just provides a different type of feedback */ +#undef HIDE_CURSOR_AFTER_MOUSEUP + +/* enable HOT_TRACKING to provide visual feedback when the mouse + moves over a scrollbar area (like Flat Scrollbars) */ +#define HOT_TRACKING + +/* enable FLAT_SCROLLBARS to include support for flat scrollbars + note that they must be enabled by the user first of all */ +#define FLAT_SCROLLBARS + +/* a normal scrollbar "snaps" its scroll-thumb back into position if + you move the mouse too far away from the window, whilst you are + dragging the thumb, that is. #undeffing this results in the thumb + never snapping back into position, no matter how far away you move + the mouse */ +#define SNAP_THUMB_BACK + +/* distance (in pixels) the mouse must move away from the thumb + during tracking to cause the thumb bar to snap back to its + starting place. Has no effect unless SNAP_THUMB_BACK is defined */ +#define THUMBTRACK_SNAPDIST 24 + +/* maximum number of inserted buttons per bar */ +#define MAX_COOLSB_BUTS 16 + +/* maximum number of coolsb windows per application. + Set to lower if you don't need many. */ +#define MAX_COOLSB 4 + +#endif /* _USERDEFINES_INCLUDED */ \ No newline at end of file -- cgit v1.2.3