aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/General/gen_ml/scrollwnd.cpp
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/General/gen_ml/scrollwnd.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/Plugins/General/gen_ml/scrollwnd.cpp')
-rw-r--r--Src/Plugins/General/gen_ml/scrollwnd.cpp2391
1 files changed, 2391 insertions, 0 deletions
diff --git a/Src/Plugins/General/gen_ml/scrollwnd.cpp b/Src/Plugins/General/gen_ml/scrollwnd.cpp
new file mode 100644
index 00000000..61a78761
--- /dev/null
+++ b/Src/Plugins/General/gen_ml/scrollwnd.cpp
@@ -0,0 +1,2391 @@
+// some code taken from (freeware) Cool ScrollBar library by J Brown
+#include "main.h"
+#include <windowsx.h>
+#include <tchar.h>
+#include "scrollwnd.h"
+#include "../winamp/wa_dlg.h"
+
+#ifndef WM_MOUSEWHEEL
+#define WM_MOUSEWHEEL 0x020A
+#endif
+
+
+extern HRESULT(WINAPI *SetWindowTheme)(HWND hwnd, LPCWSTR pszSubAppName, LPCWSTR pszSubIdList); //xp theme shit
+extern HRESULT(WINAPI *IsAppThemed)(void);
+
+static TCHAR szPropStr[] = _T("CoolSBSubclassPtr");
+
+//
+// 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 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;
+
+ScrollWnd *GetScrollWndFromHwnd(HWND hwnd)
+{
+ return (ScrollWnd *)GetProp(hwnd, szPropStr);
+}
+
+//
+// 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;
+}
+
+BOOL drawFrameControl(HDC hdc, LPRECT lprc, UINT uType, UINT state)
+{
+ HDC hdcbmp;
+ HBITMAP hbmpOld, hbmp;
+ int startx, starty;
+
+ hbmp = WADlg_getBitmap();
+ if (!hbmp) return FALSE;
+
+ hdcbmp = CreateCompatibleDC(hdc);
+ if (!hdcbmp) return FALSE;
+
+ hbmpOld = (HBITMAP)SelectObject(hdcbmp, hbmp);
+
+ startx = 0;
+ starty = 31;
+ switch (state&3)
+ {
+ case DFCS_SCROLLRIGHT: startx = 14; starty = 45; break;
+ case DFCS_SCROLLLEFT: startx = 0; starty = 45; break;
+ case DFCS_SCROLLDOWN: startx = 14; starty = 31; break;
+ }
+ if (state&DFCS_PUSHED) startx += 28;
+ StretchBlt(hdc, lprc->left, lprc->top, lprc->right - lprc->left, lprc->bottom - lprc->top, hdcbmp, startx, starty, 14, 14, SRCCOPY);
+
+ SelectObject(hdcbmp, hbmpOld);
+ DeleteDC(hdcbmp);
+ return 1;
+}
+
+//
+// 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);
+
+ 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 * 14; //GetSystemMetrics(SM_CXHSCROLL);
+ else
+ return sbar->nArrowLength;
+ }
+ else
+ {
+ if (sbar->nArrowWidth < 0)
+ return -sbar->nArrowWidth * 14; //GetSystemMetrics(SM_CYHSCROLL);
+ else
+ return sbar->nArrowWidth;
+ }
+ }
+ else if (sbar->nBarType == SB_VERT)
+ {
+ if (metric == SM_CYVERTSB)
+ {
+ if (sbar->nArrowLength < 0)
+ return -sbar->nArrowLength * 14;//GetSystemMetrics(SM_CYVSCROLL);
+ else
+ return sbar->nArrowLength;
+ }
+ else
+ {
+ if (sbar->nArrowWidth < 0)
+ return -sbar->nArrowWidth * 14;//GetSystemMetrics(SM_CXVSCROLL);
+ else
+ return sbar->nArrowWidth;
+ }
+ }
+
+ return 0;
+}
+
+//
+//
+//
+static COLORREF GetSBForeColor(void)
+{
+ return WADlg_getColor(WADLG_SCROLLBAR_FGCOLOR);
+}
+
+static COLORREF GetSBBackColor(void)
+{
+ return WADlg_getColor(WADLG_SCROLLBAR_BGCOLOR);
+}
+
+//
+// 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);
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, rect, _T(""), 0, 0);
+ 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, int pushed, int vertical)
+{
+ HBITMAP hbmp, hbmpOld;
+ hbmp = WADlg_getBitmap();
+ if (!hbmp) return;
+
+ HDC hdcbmp = CreateCompatibleDC(hdc);
+ if (!hdcbmp) return;
+
+ hbmpOld = (HBITMAP)SelectObject(hdcbmp, hbmp);
+
+#define PART1SIZE 4 //copied top
+#define PART2SIZE 5 //stretched top
+#define PART3SIZE 10 //copied middle
+#define PART4SIZE 5 //stretched bottom
+#define PART5SIZE 4 //copied bottom
+
+ if (vertical)
+ {
+ int middle = (rect->bottom - rect->top) / 2;
+ int startx = pushed ? 70 : 56;
+ //top
+ StretchBlt(hdc, rect->left, rect->top, rect->right - rect->left, PART1SIZE, hdcbmp, startx, 31, 14, PART1SIZE, SRCCOPY);
+ int p = PART1SIZE;
+ //stretched top
+ int l = middle - PART1SIZE - (PART3SIZE / 2);
+ if (l > 0)
+ {
+ StretchBlt(hdc, rect->left, rect->top + p, rect->right - rect->left, l, hdcbmp, startx, 31 + PART1SIZE, 14, PART2SIZE, SRCCOPY);
+ p += middle - PART1SIZE - (PART3SIZE / 2);
+ }
+ //copied middle
+ int m = (rect->bottom - rect->top) - PART1SIZE - PART5SIZE; //space that's available for middle
+ m = min(m, PART3SIZE);
+ if (m > 0)
+ {
+ StretchBlt(hdc, rect->left, rect->top + p, rect->right - rect->left, m, hdcbmp, startx, 31 + PART1SIZE + PART2SIZE, 14, m, SRCCOPY);
+ p += m;
+ }
+ //stretched bottom
+ l = rect->bottom - rect->top - p - PART5SIZE;
+ if (l > 0) StretchBlt(hdc, rect->left, rect->top + p, rect->right - rect->left, l, hdcbmp, startx, 31 + PART1SIZE + PART2SIZE + PART3SIZE, 14, PART4SIZE, SRCCOPY);
+ //bottom
+ StretchBlt(hdc, rect->left, rect->bottom - PART5SIZE, rect->right - rect->left, PART5SIZE, hdcbmp, startx, 31 + PART1SIZE + PART2SIZE + PART3SIZE + PART4SIZE, 14, PART5SIZE, SRCCOPY);
+ }
+ else
+ {
+ int middle = (rect->right - rect->left) / 2;
+ int starty = pushed ? 45 : 31;
+ //top
+ StretchBlt(hdc, rect->left, rect->top, PART1SIZE, rect->bottom - rect->top, hdcbmp, 84, starty, PART1SIZE, 14, SRCCOPY);
+ int p = PART1SIZE;
+ //stretched top
+ int l = middle - PART1SIZE - (PART3SIZE / 2);
+ if (l > 0)
+ {
+ StretchBlt(hdc, rect->left + p, rect->top, l, rect->bottom - rect->top, hdcbmp, 84 + PART1SIZE, starty, PART2SIZE, 14, SRCCOPY);
+ p += middle - PART1SIZE - (PART3SIZE / 2);
+ }
+ //copied middle
+ int m = (rect->right - rect->left) - PART1SIZE - PART5SIZE; //space that's available for middle
+ m = min(m, PART3SIZE);
+ if (m > 0)
+ {
+ StretchBlt(hdc, rect->left + p, rect->top, m, rect->bottom - rect->top, hdcbmp, 84 + PART1SIZE + PART2SIZE, starty, m, 14, SRCCOPY);
+ p += m;
+ }
+ //stretched bottom
+ l = rect->right - rect->left - p - PART5SIZE;
+ if (l > 0) StretchBlt(hdc, rect->left + p, rect->top, l, rect->bottom - rect->top, hdcbmp, 84 + PART1SIZE + PART2SIZE + PART3SIZE, starty, PART4SIZE, 14, SRCCOPY);
+ //bottom
+ StretchBlt(hdc, rect->right - PART5SIZE, rect->top, PART5SIZE, rect->bottom - rect->top, hdcbmp, 84 + PART1SIZE + PART2SIZE + PART3SIZE + PART4SIZE, starty, PART5SIZE, 14, SRCCOPY);
+ }
+
+ SelectObject(hdcbmp, hbmpOld);
+ DeleteDC(hdcbmp);
+}
+
+//
+// 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;
+}
+
+//
+// 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;
+
+ //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 PostCustomPrePostPaint0(HWND hwnd, HDC hdc, SCROLLBAR *sb, UINT dwStage)
+{
+ return 0;
+}
+
+static LRESULT PostCustomDrawNotify0(HWND hwnd, HDC hdc, UINT nBar, RECT *prect, UINT nItem, BOOL fMouseDown, BOOL fMouseOver, BOOL fInactive)
+{
+ return 0;
+}
+
+// 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.
+//
+#define PostCustomDrawNotify 1 ? (void)0 : PostCustomDrawNotify0
+#define PostCustomPrePostPaint 1 ? (void)0 : PostCustomPrePostPaint0
+
+static LRESULT PostMouseNotify0(HWND hwnd, UINT msg, UINT nBar, RECT *prect, UINT nCmdId, POINT pt)
+{
+ return 0;
+}
+
+#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;
+ BOOL fCustomDraw = 0;
+
+ BOOL fMouseDownL = 0, fMouseOverL = 0;
+ BOOL fMouseDownR = 0, fMouseOverR = 0;
+
+ COLORREF crCheck1 = GetSBForeColor();
+ COLORREF crCheck2 = GetSBBackColor();
+ COLORREF crInverse1 = WADlg_getColor(WADLG_SCROLLBAR_INV_FGCOLOR);
+ COLORREF crInverse2 = WADlg_getColor(WADLG_SCROLLBAR_INV_BGCOLOR);
+
+ 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;
+
+ 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)
+ {
+ fMouseDownL = (uDrawFlags == HTSCROLL_LEFT);
+ fMouseDownR = (uDrawFlags == HTSCROLL_RIGHT);
+ }
+
+ //
+ // 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, FALSE);
+ }
+ else
+ {
+ int track = 0;
+ if (uCurrentScrollbar == (UINT)sb->nBarType) track = GetScrollWndFromHwnd(hwnd)->fThumbTracking;
+ DrawBlankButton(hdc, &thumb, uDEFlat, track, sb->nBarType == SB_VERT);
+ }
+ 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
+ {
+ DrawBlankButton(hdc, &ctrl, uDEFlat, 0, sb->nBarType == SB_VERT);
+
+ }
+ 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);
+ }
+
+ }
+
+ 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);
+}
+
+//
+// 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);
+}
+
+static LRESULT NCPaint(ScrollWnd *sw, HWND hwnd, WPARAM wParam, LPARAM lParam)
+{
+ SCROLLBAR *sb;
+ HDC hdc;
+ HRGN hrgn;
+ RECT winrect, rect;
+ HRGN clip;
+ 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
+ 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)
+ {
+ //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);
+
+ 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)
+ {
+ //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);
+
+ 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 = GetWindowLongPtr(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;
+ SetWindowLongPtr(hwnd, GWL_STYLE, dwStyle & ~(WS_VSCROLL | WS_HSCROLL));
+ }
+
+ ret = (sw->fWndUnicode) ? CallWindowProcW(sw->oldproc, hwnd, WM_NCPAINT, (WPARAM)hrgn, lParam) :
+ CallWindowProcA(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, WADlg_getColor(WADLG_SCROLLBAR_DEADAREA_COLOR));
+ }
+ }
+
+ 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 = GET_X_LPARAM(lParam);
+ pt.y = GET_Y_LPARAM(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 (sw->fWndUnicode) ? CallWindowProcW(sw->oldproc, hwnd, WM_NCHITTEST, wParam, lParam) :
+ CallWindowProcA(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;
+
+ //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);
+ }
+}
+
+//
+// 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;
+ POINT pt;
+
+ pt.x = GET_X_LPARAM(lParam);
+ pt.y = GET_Y_LPARAM(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, GET_X_LPARAM(lParam), GET_Y_LPARAM(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, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
+ }
+ //
+ // NORMAL PROCESSING
+ //
+ else
+ {
+ uCurrentScrollPortion = HTSCROLL_NONE;
+ return (sw->fWndUnicode) ? CallWindowProcW(sw->oldproc, hwnd, WM_NCLBUTTONDOWN, wParam, lParam) :
+ CallWindowProcA(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
+ 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);
+
+ //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;
+ 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);
+ sw->update();
+ break;
+ default:
+ return (sw->fWndUnicode) ? CallWindowProcW(sw->oldproc, hwnd, WM_NCLBUTTONDOWN, wParam, lParam) :
+ CallWindowProcA(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;
+ POINT pt;
+ RECT winrect;
+
+ //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 = GET_X_LPARAM(lParam);
+ pt.y = GET_Y_LPARAM(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)
+ {
+ //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:
+
+ sw->update();
+
+ //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 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();
+ }*/
+ }
+
+ //sw->update();
+
+ return (sw->fWndUnicode) ? CallWindowProcW(sw->oldproc, hwnd, WM_LBUTTONUP, wParam, lParam) :
+ CallWindowProcA(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);
+
+ 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
+ {
+ DrawBlankButton(hdc, &rc2, flatflag, 1, sbar->nBarType == SB_VERT);
+ }
+
+ 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)
+ {
+
+ if (sbar->flags & SCROLLBAR_LISTVIEW)
+ {
+ // only for listviews
+ if (sbar->nBarType == SB_HORZ)
+ {
+ SCROLLINFO info;
+ info.cbSize = sizeof(SCROLLINFO);
+ info.fMask = SIF_TRACKPOS;
+ if (GetScrollInfo(hwnd, SB_HORZ, &info))
+ {
+ int nPos = info.nTrackPos;
+ SendMessage(hwnd, LVM_SCROLL, pos - nPos, 0);
+ SetScrollInfo(hwnd, sbar->nBarType, &info, FALSE);
+ }
+ }
+ else if (sbar->nBarType == SB_VERT)
+ {
+ SCROLLINFO info;
+ info.cbSize = sizeof(SCROLLINFO);
+ info.fMask = SIF_TRACKPOS;
+ if (GetScrollInfo(hwnd, SB_VERT, &info))
+ {
+ int nPos = info.nTrackPos;
+ SendMessage(hwnd, LVM_SCROLL, 0, (pos - nPos)*14); //BIG FUCKO: get the text height size
+ SetScrollInfo(hwnd, sbar->nBarType, &info, FALSE);
+ }
+ }
+ }
+ else
+ {
+ si->nTrackPos = pos;
+ SCROLLINFO info;
+ info.cbSize = sizeof(SCROLLINFO);
+ info.fMask = SIF_TRACKPOS;
+ info.nTrackPos = pos;
+
+ SetScrollInfo(hwnd, sbar->nBarType, &info, FALSE);
+ SendScrollMessage(hwnd, uScrollTimerMsg, SB_THUMBTRACK, pos);
+ }
+ }
+
+ nLastPos = pos;
+
+ 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;
+ POINT pt;
+ RECT winrect;
+
+ if (sw->fThumbTracking == TRUE)
+ {
+ int x, y;
+ lParam = GetMessagePos();
+ x = GET_X_LPARAM(lParam);
+ y = GET_Y_LPARAM(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 (sw->fWndUnicode) ? CallWindowProcW(sw->oldproc, hwnd, WM_MOUSEMOVE, wParam, lParam) :
+ CallWindowProcA(sw->oldproc, hwnd, WM_MOUSEMOVE, wParam, lParam);
+ }
+ else
+ {
+ LPARAM nlParam;
+ SCROLLBAR *sb = &sw->sbarHorz;
+
+ nlParam = GetMessagePos();
+
+ GetWindowRect(hwnd, &winrect);
+
+ pt.x = GET_X_LPARAM(nlParam);
+ pt.y = GET_Y_LPARAM(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));
+ UINT 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
+ static UINT lastportion = 0;
+ switch (uCurrentScrollPortion)
+ {
+ //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 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;
+
+ //must return zero here, because we might get cursor anomilies
+ //CallWindowProc(sw->oldproc, hwnd, WM_MOUSEMOVE, wParam, lParam);
+ return 0;
+
+ }
+}
+
+//
+// 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 = (sw->fWndUnicode) ? CallWindowProcW(sw->oldproc, hwnd, WM_NCCALCSIZE, wParam, lParam) :
+ CallWindowProcA(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;
+
+ //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
+ return (sw->fWndUnicode) ? CallWindowProcW(sw->oldproc, hwnd, WM_NCMOUSEMOVE, wHitTest, lParam) :
+ CallWindowProcA(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 (swnd->fWndUnicode) ? CallWindowProcW(swnd->oldproc, hwnd, WM_TIMER, wTimerId, lParam) :
+ CallWindowProcA(swnd->oldproc, hwnd, WM_TIMER, wTimerId, lParam);
+
+ }
+
+ //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);
+
+ swnd->update();
+ return 0;
+ }
+ else
+ {
+ return (swnd->fWndUnicode) ? CallWindowProcW(swnd->oldproc, hwnd, WM_TIMER, wTimerId, lParam) :
+ CallWindowProcA(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 (swnd->fWndUnicode) ? CallWindowProcW(swnd->oldproc, hwnd, msg, wParam, lParam) :
+ CallWindowProcA(swnd->oldproc, hwnd, msg, wParam, lParam);
+}
+
+static UINT curTool = -1;
+static LRESULT CoolSB_Notify(ScrollWnd *swnd, HWND hwnd, WPARAM wParam, LPARAM lParam)
+{
+ return (swnd->fWndUnicode) ? CallWindowProcW(swnd->oldproc, hwnd, WM_NOTIFY, wParam, lParam) :
+ CallWindowProcA(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)
+{
+ return (swnd->fWndUnicode) ? CallWindowProcW(swnd->oldproc, hwnd, WM_SETCURSOR, wParam, lParam) :
+ CallWindowProcA(swnd->oldproc, hwnd, WM_SETCURSOR, wParam, lParam);
+}
+
+//
+// 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);
+
+ if (!swnd || !swnd->oldproc)
+ {
+ return (IsWindowUnicode(hwnd)) ? DefWindowProcW(hwnd, message, wParam, lParam) :
+ DefWindowProcA(hwnd, message, wParam, lParam);
+ }
+
+ 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;
+ delete(swnd);
+
+ //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 (IsWindowUnicode(hwnd)) ? CallWindowProcW(oldproc, hwnd, message, wParam, lParam) : CallWindowProcA(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:
+ 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++);
+ return NCLButtonDown(swnd, hwnd, wParam, lParam);
+
+
+ case WM_LBUTTONUP:
+ //TRACE("WM_LBUTTONUP %d\n", count++);
+ 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);
+ }
+ break;
+
+ case WM_NCMOUSEMOVE:
+ {
+ static LPARAM 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)
+ {
+ lastpos = lParam;
+ }
+ }
+
+ return NCMouseMove(swnd, hwnd, wParam, lParam);
+
+
+ case WM_SETCURSOR:
+ return CoolSB_SetCursor(swnd, hwnd, wParam, lParam);
+
+ case WM_CAPTURECHANGED:
+ break;
+
+ case WM_ERASEBKGND:
+ if (swnd && !swnd->fThumbTracking && uCurrentScrollPortion == HTSCROLL_NONE)
+ {
+ //disable windows scrollbar painting (fixes gfx repainting weirdness)
+ int style = GetWindowLong(hwnd, GWL_STYLE);
+ if (style&(WS_HSCROLL | WS_VSCROLL))
+ {
+ SetWindowLong(hwnd, GWL_STYLE, style&~(WS_HSCROLL | WS_VSCROLL));
+ }
+
+ LRESULT ret = (swnd->fWndUnicode) ? CallWindowProcW(swnd->oldproc, hwnd, message, wParam, lParam) :
+ CallWindowProcA(swnd->oldproc, hwnd, message, wParam, lParam);
+ swnd->update();
+ return ret;
+ }
+ break;
+
+ //needed if we want mousewheel to work properly because we disable the styles in WM_ERASEBKGND...
+ case WM_MOUSEWHEEL:
+ {
+ int style = GetWindowLong(hwnd, GWL_STYLE);
+ swnd->bPreventStyleChange = TRUE;
+ SetWindowLong(hwnd, GWL_STYLE, style | (swnd->sbarHorz.fScrollVisible ? WS_HSCROLL : 0) | (swnd->sbarVert.fScrollVisible ? WS_VSCROLL : 0));
+ LRESULT ret = (swnd->fWndUnicode) ? CallWindowProcW(swnd->oldproc, hwnd, message, wParam, lParam) :
+ CallWindowProcA(swnd->oldproc, hwnd, message, wParam, lParam);
+ SetWindowLongPtr(hwnd, GWL_STYLE, style);
+ swnd->bPreventStyleChange = FALSE;
+ return ret;
+ }
+
+ case WM_USER + 0x3443: //manually sent by other windows (like columns header for ex.)
+ if (swnd) swnd->update();
+ break;
+
+ default:
+ break;
+ }
+ return (swnd->fWndUnicode) ? CallWindowProcW(swnd->oldproc, hwnd, message, wParam, lParam) :
+ CallWindowProcA(swnd->oldproc, hwnd, message, wParam, lParam);
+}
+
+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;
+}
+
+//
+// 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;
+ }
+}
+
+//
+// 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;
+}
+
+static void RedrawNonClient(HWND hwnd, BOOL fFrameChanged)
+{
+ if (fFrameChanged == FALSE)
+ {
+ 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);
+ }
+}
+
+ScrollWnd::ScrollWnd(HWND hwnd, int flags)
+{
+ SCROLLINFO *si;
+ RECT rect;
+ DWORD dwCurStyle;
+
+ bars = 0;
+ oldproc = NULL;
+ memset(&sbarHorz, 0, sizeof(sbarHorz));
+ memset(&sbarVert, 0, sizeof(sbarVert));
+ sbarHorz.flags = flags;
+ sbarVert.flags = flags;
+ fThumbTracking = 0;
+ fLeftScrollbar = 0;
+ cxLeftEdge = cxRightEdge = cyTopEdge = cyBottomEdge = 0;
+ bPreventStyleChange = 0;
+ m_disable_hscroll = 0;
+ m_xp_theme_disabled = 0;
+
+ m_hwnd = hwnd;
+
+ GetClientRect(hwnd, &rect);
+
+ si = &sbarHorz.scrollInfo;
+ si->cbSize = sizeof(SCROLLINFO);
+ si->fMask = SIF_ALL;
+ GetScrollInfo(hwnd, SB_HORZ, si);
+
+ si = &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)
+ fLeftScrollbar = TRUE;
+ else
+ fLeftScrollbar = FALSE;
+
+ dwCurStyle = GetWindowLong(hwnd, GWL_STYLE);
+
+ SetProp(hwnd, szPropStr, (HANDLE)this);
+
+ //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)
+ sbarHorz.fScrollFlags = CSBS_VISIBLE;
+
+ if (dwCurStyle & WS_VSCROLL)
+ sbarVert.fScrollFlags = CSBS_VISIBLE;
+
+ //need to be able to distinguish between horizontal and vertical
+ //scrollbars in some instances
+ sbarHorz.nBarType = SB_HORZ;
+ sbarVert.nBarType = SB_VERT;
+
+ sbarHorz.fFlatScrollbar = CSBS_NORMAL;
+ sbarVert.fFlatScrollbar = CSBS_NORMAL;
+
+ //set the default arrow sizes for the scrollbars
+ sbarHorz.nArrowLength = SYSTEM_METRIC;
+ sbarHorz.nArrowWidth = SYSTEM_METRIC;
+ sbarVert.nArrowLength = SYSTEM_METRIC;
+ sbarVert.nArrowWidth = SYSTEM_METRIC;
+
+ bPreventStyleChange = FALSE;
+
+ fWndUnicode = IsWindowUnicode(hwnd);
+ oldproc = (WNDPROC)(LONG_PTR) ((fWndUnicode) ? SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)CoolSBWndProc) :
+ SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)CoolSBWndProc));
+
+ CoolSB_SetMinThumbSize(hwnd, SB_BOTH, CoolSB_GetDefaultMinThumbSize());
+
+ //send the window a frame changed message to update the scrollbars
+ RedrawNonClient(hwnd, TRUE);
+
+ //disable XP styles
+ if (SetWindowTheme && !m_xp_theme_disabled)
+ {
+ SetWindowTheme(m_hwnd, L" ", L" ");
+ m_xp_theme_disabled = 1;
+
+ }
+
+}
+
+BOOL WINAPI CoolSB_ShowScrollBar(HWND hwnd, int wBar, BOOL fShow)
+{
+ SCROLLBAR *sbar;
+ BOOL bFailed = FALSE;
+ DWORD dwStyle = GetWindowLong(hwnd, GWL_STYLE);
+
+ 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
+ {
+ SetWindowPos(hwnd, 0, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
+ SWP_NOACTIVATE | SWP_FRAMECHANGED);
+
+ return TRUE;
+ }
+}
+
+ScrollWnd::~ScrollWnd()
+{
+ if (oldproc)
+ {
+ ((fWndUnicode) ? SetWindowLongPtrW(m_hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)oldproc) :
+ SetWindowLongPtrA(m_hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)oldproc));
+ }
+ RemoveProp(m_hwnd, szPropStr);
+ RedrawNonClient(m_hwnd, TRUE);
+}
+
+void ScrollWnd::update()
+{
+ int dohorz = 0, dovert = 0;
+
+ SCROLLINFO tsi = {sizeof(SCROLLINFO), SIF_ALL, };
+
+ if (!m_disable_hscroll)
+ {
+ GetScrollInfo(m_hwnd, SB_HORZ, &tsi);
+ if (memcmp(&tsi, &sbarHorz.scrollInfo, sizeof(SCROLLINFO)))
+ {
+ memcpy(&sbarHorz.scrollInfo, &tsi, sizeof(SCROLLINFO));
+ dohorz = 1;
+ }
+ }
+ GetScrollInfo(m_hwnd, SB_VERT, &tsi);
+ if (memcmp(&tsi, &sbarVert.scrollInfo, sizeof(SCROLLINFO)))
+ {
+ memcpy(&sbarVert.scrollInfo, &tsi, sizeof(SCROLLINFO));
+ dovert = 1;
+ }
+
+ BOOL fRecalcFrame = FALSE;
+ if (dohorz) updatesb(SB_HORZ, &fRecalcFrame);
+ if (dovert) updatesb(SB_VERT, &fRecalcFrame);
+
+ if (dohorz || dovert) RedrawNonClient(m_hwnd, fRecalcFrame);
+}
+
+void ScrollWnd::updatesb(int fnBar, BOOL *fRecalcFrame)
+{
+ SCROLLBAR *sbar = (fnBar == SB_HORZ ? &sbarHorz : &sbarVert);
+ SCROLLINFO *mysi = &sbar->scrollInfo;
+
+ if (mysi->nPage > (UINT)mysi->nMax
+ || (mysi->nPage == (UINT)mysi->nMax && mysi->nMax == 0)
+ || mysi->nMax <= mysi->nMin)
+ {
+ if (sbar->fScrollVisible)
+ {
+ CoolSB_ShowScrollBar(m_hwnd, fnBar, FALSE);
+ *fRecalcFrame = TRUE;
+ }
+ }
+ else
+ {
+ if (!sbar->fScrollVisible && mysi->nPage > 0)
+ {
+ CoolSB_ShowScrollBar(m_hwnd, fnBar, TRUE);
+ *fRecalcFrame = TRUE;
+ }
+ else if (sbar->fScrollVisible && mysi->nPage == 0)
+ {
+ CoolSB_ShowScrollBar(m_hwnd, fnBar, FALSE);
+ *fRecalcFrame = TRUE;
+ }
+ }
+}
+
+void ScrollWnd::disableHorzScroll()
+{
+ m_disable_hscroll = 1;
+ sbarHorz.fScrollFlags = 0;
+}
+
+#if 0 // unused
+int ScrollWnd::setScrollInfo(int fnBar, LPSCROLLINFO lpsi, BOOL fRedraw)
+{
+ SCROLLINFO *mysi;
+ SCROLLBAR *sbar;
+ BOOL fRecalcFrame = FALSE;
+
+ if (!lpsi)
+ return FALSE;
+
+ if (fnBar == SB_HORZ) mysi = &sbarHorz.scrollInfo;
+ else mysi = &sbarVert.scrollInfo;
+
+ 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(m_hwnd, fnBar);
+
+ if ((lpsi->fMask & SIF_DISABLENOSCROLL) || (sbar->fScrollFlags & CSBS_THUMBALWAYS))
+ {
+ if (!sbar->fScrollVisible)
+ {
+ CoolSB_ShowScrollBar(m_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(m_hwnd, fnBar, FALSE);
+ fRecalcFrame = TRUE;
+ }
+ }
+ else
+ {
+ if (!sbar->fScrollVisible)
+ {
+ CoolSB_ShowScrollBar(m_hwnd, fnBar, TRUE);
+ fRecalcFrame = TRUE;
+ }
+ }
+ }
+
+ if (fRedraw && !fThumbTracking)
+ RedrawNonClient(m_hwnd, fRecalcFrame);
+
+ return mysi->nPos;
+}
+#endif \ No newline at end of file