aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/General/gen_ml/skinnedscrollwnd.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Plugins/General/gen_ml/skinnedscrollwnd.cpp')
-rw-r--r--Src/Plugins/General/gen_ml/skinnedscrollwnd.cpp3285
1 files changed, 3285 insertions, 0 deletions
diff --git a/Src/Plugins/General/gen_ml/skinnedscrollwnd.cpp b/Src/Plugins/General/gen_ml/skinnedscrollwnd.cpp
new file mode 100644
index 00000000..64a409b9
--- /dev/null
+++ b/Src/Plugins/General/gen_ml/skinnedscrollwnd.cpp
@@ -0,0 +1,3285 @@
+// some code taken from (freeware) Cool ScrollBar library by J Brown
+#include "./skinnedscrollwnd.h"
+#include "main.h"
+#include <commctrl.h>
+#include <windowsx.h>
+#include "../winamp/wa_dlg.h"
+#include "api__gen_ml.h"
+#include "./colors.h"
+#include <tataki/bitmap/bitmap.h>
+#include <tataki/bitmap/autobitmap.h>
+#include <tataki/canvas/canvas.h>
+#include <api/wnd/api_window.h>
+#include "./stockobjects.h"
+
+
+/* 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
+/* 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 128
+// 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 0x0004
+#define CSBS_VISIBLE 0x0008
+#define CSBS_TRACKING 0x0010
+#define CSBS_FLATSB 0x0020
+#define CSBS_BTNVISBEFORE 0x0040 //if the buttons to the left are visible
+#define CSBS_BTNVISAFTER 0x0080 //if the buttons to the right are visible
+#define CSBS_HOVERING 0x0100 //if the buttons to the right are visible
+
+//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
+
+#define DFCS_HOVER 0x800
+//
+// 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 9
+#define MINTHUMBSIZE_2000 7
+
+//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)
+
+// SCROLLBAR datatype. There are two of these structures per window
+typedef struct _SCROLLBAR
+{
+ UINT fScrollFlags; //flags
+ BOOL fScrollVisible; //if this scrollbar visible?
+ SCROLLINFO scrollInfo; //positional data (range, position, page size etc)
+
+ //data for inserted buttons
+ int nButSizeBefore; //size to the left / above the bar
+ int nButSizeAfter; //size to the right / below the bar
+
+ int nMinThumbSize;
+ int nBarType; //SB_HORZ / SB_VERT
+
+} SCROLLBAR;
+
+static WORD wCheckPat[8] =
+{
+ 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555
+};
+
+
+// scrollwnd styles
+#define SWS_UPDATEFRAME 0x0001
+#define SWS_LEFT 0x0002
+#define SWS_DISABLENOSCROLL 0x0004
+#define SWS_HIDEHSCROLL 0x0008
+#define SWS_LISTVIEW 0x0010
+#define SWS_TREEVIEW 0x0020
+#define SWS_HIDEVSCROLL 0x0040
+#define SWS_COMBOLBOX 0x0080
+#define SWS_USEFREEFORM 0x0100
+
+//
+// PRIVATE INTERNAL FUNCTIONS
+//
+#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
+
+#ifndef WM_MOUSEWHEEL
+#define WM_MOUSEWHEEL 0x020A
+#endif
+
+
+#define INACTIVEBAR_ALPHA 127
+
+//
+// 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
+static int trackThumbPos;
+//
+// Temporary state used to auto-generate timer messages
+//
+static UINT uScrollTimerMsg = 0;
+static UINT uScrollTimerPortion = HTSCROLL_NONE;
+static UINT_PTR uScrollTimerId = 0;
+static HWND hwndCurCoolSB = 0;
+
+static INT bUseUpdateRgn = -1;
+static BOOL bDoHover=FALSE;
+static BOOL ignoreCaptureChange = FALSE;
+static BOOL captureSet = FALSE;
+static HBRUSH hbrChecked = NULL;
+
+#define GetSBForeColor() WADlg_getColor(WADLG_SCROLLBAR_FGCOLOR)
+#define GetSBBackColor() WADlg_getColor(WADLG_SCROLLBAR_BGCOLOR)
+
+// Send a WM_VSCROLL or WM_HSCROLL message
+#define SendScrollMessage(__hwnd, __srcMsg, __srcId, __pos) ::SendMessageW(__hwnd, __srcMsg, (MAKEWPARAM(__srcId, __pos)), 0)
+
+static UINT GetPortion(SCROLLBAR *sb, HWND hwnd, RECT *rect, int x, int y, DWORD scrollFlags);
+
+static void RenderBaseTexture(Canvas *canvas, const RECT *r, HWND hwnd)
+{
+ // TODO: find the ifc_window * object for the media library container, and call renderBaseTexture on it
+ if (WASABI_API_WND)
+ {
+ HWND checkWnd = GetParent(hwnd);
+ while (checkWnd)
+ {
+ ifc_window *window = WASABI_API_WND->rootWndFromOSHandle(checkWnd);
+ if (window && window->getRenderBaseTexture())
+ {
+ window->renderBaseTexture(canvas, r);
+ return;
+ }
+ checkWnd = GetParent(checkWnd);
+ }
+ }
+
+ // fallback code
+ COLORREF bgcolor = WADlg_getColor(WADLG_WNDBG/*WADLG_SCROLLBAR_BGCOLOR*/);
+ canvas->fillRect(r, bgcolor);
+}
+
+// swap the rectangle's x coords with its y coords
+static void __stdcall RotateRect(RECT *rect)
+{
+ LONG 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
+#define RotateRect0(__psb, __prc) ((__psb && __psb->nBarType == SB_VERT) ? RotateRect(__prc) : 0)
+
+static bool UseFreeformScrollbars()
+{
+ if (config_use_ff_scrollbars && WASABI_API_SKIN && WASABI_API_SKIN->skin_isLoaded())
+ {
+ return WASABI_API_SKIN->skin_getVersion() >= 1.3;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+// Calculate if the SCROLLINFO members produce an enabled or disabled scrollbar
+static BOOL IsScrollInfoActive(SCROLLINFO *si)
+{
+ return (si->nPage <= (UINT)si->nMax && si->nMax > si->nMin && si->nMax != 0);
+}
+
+// Return if the specified scrollbar is enabled or not
+static BOOL IsScrollbarActive(SCROLLBAR *sb)
+{
+ return (((sb->fScrollFlags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH) ||
+ !(sb->fScrollFlags & CSBS_THUMBALWAYS) && !IsScrollInfoActive(&sb->scrollInfo)) ? FALSE : TRUE;
+}
+
+enum
+{
+ HORIZ_LEFT,
+ HORIZ_LEFT_PRESSED,
+ HORIZ_LEFT_HOVER,
+ HORIZ_LEFT_INACTIVE,
+ HORIZ_RIGHT,
+ HORIZ_RIGHT_PRESSED,
+ HORIZ_RIGHT_HOVER,
+ HORIZ_RIGHT_INACTIVE,
+ VERT_UP,
+ VERT_UP_PRESSED,
+ VERT_UP_HOVER,
+ VERT_UP_INACTIVE,
+ VERT_DOWN,
+ VERT_DOWN_PRESSED,
+ VERT_DOWN_HOVER,
+ VERT_DOWN_INACTIVE,
+};
+
+static int GetBitmapEnum(UINT state, BOOL hover)
+{
+ int offset=0;
+ if (state&DFCS_PUSHED)
+ offset=1;
+ if (state&DFCS_INACTIVE)
+ offset=3;
+ else if (hover)
+ offset=2;
+
+ switch (state&3)
+ {
+ case DFCS_SCROLLRIGHT:
+ return HORIZ_RIGHT+offset;
+ case DFCS_SCROLLLEFT:
+ return HORIZ_LEFT+offset;
+ case DFCS_SCROLLDOWN:
+ return VERT_DOWN+offset;
+ default://case DFCS_SCROLLUP:
+ return VERT_UP+offset;
+ }
+}
+
+class ScrollBitmaps
+{
+public:
+ ScrollBitmaps() : v_up(L"wasabi.scrollbar.vertical.background.top"),
+ v_down(L"wasabi.scrollbar.vertical.background.bottom"),
+ v_mid(L"wasabi.scrollbar.vertical.background.middle"),
+ h_left(L"wasabi.scrollbar.horizontal.background.left"),
+ h_mid(L"wasabi.scrollbar.horizontal.background.middle"),
+ h_right(L"wasabi.scrollbar.horizontal.background.right")
+ {
+ }
+ AutoSkinBitmap v_up, v_down, v_mid, h_left, h_mid, h_right;
+};
+
+static ScrollBitmaps *scrollBitmaps=0;
+
+void SkinnedScrollWnd_Init()
+{
+ scrollBitmaps = new ScrollBitmaps();
+}
+
+void SkinnedScrollWnd_Quit()
+{
+ if (scrollBitmaps)
+ {
+ delete scrollBitmaps;
+ scrollBitmaps=0;
+ }
+}
+
+static HBITMAP hbmpCachedDib = NULL;
+
+// Paint a checkered rectangle, with each alternate pixel being assigned a different colour
+
+static BOOL DrawFrameCtrl(HDC hdc, LPRECT lprc, UINT uType, UINT state, BOOL hover, BOOL freeform)
+{
+ int startx, starty, alpha = 255;
+
+ const wchar_t *bitmapid=0;
+ const wchar_t *backgroundid=0;
+ SkinBitmap *bg=0;
+ switch (GetBitmapEnum(state, hover))
+ {
+ case HORIZ_LEFT:
+ bitmapid = L"wasabi.scrollbar.horizontal.left";
+ if (scrollBitmaps)
+ bg=scrollBitmaps->h_left.getBitmap();
+ startx = 0; starty = 45; break;
+ case HORIZ_LEFT_PRESSED:
+ bitmapid = L"wasabi.scrollbar.horizontal.left.pressed";
+ if (scrollBitmaps)
+ bg=scrollBitmaps->h_left.getBitmap();
+ startx = 28; starty = 45; break;
+ case HORIZ_LEFT_HOVER:
+ bitmapid = L"wasabi.scrollbar.horizontal.left.hover";
+ if (scrollBitmaps)
+ bg=scrollBitmaps->h_left.getBitmap();
+ startx = 0; starty = 45; break;
+ case HORIZ_LEFT_INACTIVE:
+ alpha = INACTIVEBAR_ALPHA;
+ bitmapid = L"wasabi.scrollbar.horizontal.left";
+ if (scrollBitmaps)
+ bg=scrollBitmaps->h_left.getBitmap();
+ startx = 0; starty = 45; break;
+ case HORIZ_RIGHT:
+ bitmapid = L"wasabi.scrollbar.horizontal.right";
+ if (scrollBitmaps)
+ bg=scrollBitmaps->h_right.getBitmap();
+ startx = 14; starty = 45; break;
+ case HORIZ_RIGHT_PRESSED:
+ bitmapid = L"wasabi.scrollbar.horizontal.right.pressed";
+ if (scrollBitmaps)
+ bg=scrollBitmaps->h_right.getBitmap();
+ startx = 42; starty = 45; break;
+ case HORIZ_RIGHT_HOVER:
+ bitmapid = L"wasabi.scrollbar.horizontal.right.hover";
+ if (scrollBitmaps)
+ bg=scrollBitmaps->h_right.getBitmap();
+ startx = 14; starty = 45; break;
+ case HORIZ_RIGHT_INACTIVE:
+ alpha = INACTIVEBAR_ALPHA;
+ bitmapid = L"wasabi.scrollbar.horizontal.right";
+ if (scrollBitmaps)
+ bg=scrollBitmaps->h_right.getBitmap();
+ startx = 14; starty = 45; break;
+ case VERT_UP:
+ bitmapid = L"wasabi.scrollbar.vertical.left";
+ if (scrollBitmaps)
+ bg=scrollBitmaps->v_up.getBitmap();
+ startx = 0; starty = 31; break;
+ case VERT_UP_PRESSED:
+ bitmapid = L"wasabi.scrollbar.vertical.left.pressed";
+ if (scrollBitmaps)
+ bg=scrollBitmaps->v_up.getBitmap();
+ startx = 28; starty = 31; break;
+ case VERT_UP_HOVER:
+ bitmapid = L"wasabi.scrollbar.vertical.left.hover";
+ if (scrollBitmaps)
+ bg=scrollBitmaps->v_up.getBitmap();
+ startx = 0; starty = 31; break;
+ case VERT_UP_INACTIVE:
+ alpha = INACTIVEBAR_ALPHA;
+ bitmapid = L"wasabi.scrollbar.vertical.left";
+ if (scrollBitmaps)
+ bg=scrollBitmaps->v_up.getBitmap();
+ startx = 0; starty = 31; break;
+
+ case VERT_DOWN:
+ bitmapid = L"wasabi.scrollbar.vertical.right";
+ if (scrollBitmaps)
+ bg=scrollBitmaps->v_down.getBitmap();
+ startx = 14; starty = 31; break;
+ case VERT_DOWN_PRESSED:
+ bitmapid = L"wasabi.scrollbar.vertical.right.pressed";
+ if (scrollBitmaps)
+ bg=scrollBitmaps->v_down.getBitmap();
+ startx = 42; starty = 31; break;
+ case VERT_DOWN_HOVER:
+ bitmapid = L"wasabi.scrollbar.vertical.right.hover";
+ if (scrollBitmaps)
+ bg=scrollBitmaps->v_down.getBitmap();
+ startx = 14; starty = 31; break;
+ case VERT_DOWN_INACTIVE:
+ alpha = INACTIVEBAR_ALPHA;
+ bitmapid = L"wasabi.scrollbar.vertical.right";
+ if (scrollBitmaps)
+ bg=scrollBitmaps->v_down.getBitmap();
+ startx = 14; starty = 31; break;
+ }
+
+ if (freeform)
+ {
+ SkinBitmap bmp(bitmapid);
+ if (!bmp.isInvalid() && bg && !bg->isInvalid())
+ {
+ DCCanvas canvas(hdc);
+ bg->stretchToRectAlpha(&canvas, lprc, alpha);
+ bmp.stretchToRectAlpha(&canvas, lprc, alpha);
+ return 1;
+ }
+ }
+
+ // fallback code
+ HDC hdcbmp;
+ HBITMAP hbmpOld, hbmp;
+
+ hbmp = WADlg_getBitmap();
+ if (!hbmp) return FALSE;
+
+ hdcbmp = (HDC)MlStockObjects_Get(CACHED_DC);
+ if (!hdcbmp) return FALSE;
+
+ hbmpOld = (HBITMAP)SelectObject(hdcbmp, hbmp);
+
+
+
+ if (255 == alpha)
+ StretchBlt(hdc, lprc->left, lprc->top, lprc->right - lprc->left, lprc->bottom - lprc->top, hdcbmp, startx, starty, 14, 14, SRCCOPY);
+ else
+ {
+ HDC hdcTmp = CreateCompatibleDC(hdc);
+
+ DIBSECTION dibSection;
+ if (NULL == hbmpCachedDib ||
+ sizeof(DIBSECTION) != GetObjectW(hbmpCachedDib, sizeof(DIBSECTION), &dibSection)
+ || dibSection.dsBm.bmWidth < (lprc->right - lprc->left) || ABS(dibSection.dsBm.bmHeight) < (lprc->bottom - lprc->top))
+ {
+ if (hbmpCachedDib) DeleteObject(hbmpCachedDib);
+
+ BITMAPINFOHEADER bi;
+ ZeroMemory(&bi, sizeof(BITMAPINFOHEADER));
+ bi.biSize = sizeof(BITMAPINFOHEADER);
+ bi.biWidth = lprc->right - lprc->left;
+ bi.biHeight = -(lprc->bottom - lprc->top);
+ bi.biPlanes = 1;
+ bi.biBitCount = 32;
+ bi.biCompression = BI_RGB;
+ hbmpCachedDib = CreateDIBSection(hdc, (BITMAPINFO*)&bi, DIB_RGB_COLORS, (VOID**)&dibSection.dsBm.bmBits, NULL, 0);
+ dibSection.dsBm.bmHeight = bi.biHeight;
+ dibSection.dsBm.bmWidth = bi.biWidth;
+ }
+
+ ASSERT(hbmpCachedDib != 0);
+
+ HBITMAP hbmpTmp = (HBITMAP)SelectObject(hdcTmp, hbmpCachedDib);
+
+ StretchBlt(hdcTmp, 0, 0, lprc->right - lprc->left, lprc->bottom - lprc->top, hdcbmp, startx, starty, 14, 14, SRCCOPY);
+
+ LONG pitch = dibSection.dsBm.bmWidth*4, cy = lprc->bottom - lprc->top, x;
+ LPBYTE cursor, line;
+
+ COLORREF rgbBk = WADlg_getColor(WADLG_WNDBG);// BlendColors(GetSBBackColor(), WADlg_getColor(WADLG_ITEMBG), ((float)INACTIVEBAR_ALPHA)/255.0f);
+
+ BYTE k = (((255 - alpha)*255 + 127)/255);
+ BYTE r = (GetRValue(rgbBk)*k + 127)/255, g = (GetGValue(rgbBk)*k + 127)>>8, b = (GetBValue(rgbBk)*k + 127)/255;
+
+ for (line = (BYTE*)dibSection.dsBm.bmBits; cy-- != 0; line += pitch )
+ {
+ for (x = (lprc->right - lprc->left), cursor = line; x-- != 0; cursor += 4)
+ {
+ cursor[0] = (cursor[0]*alpha)/255 + b;
+ cursor[1] = (cursor[1]*alpha)/255 + g;
+ cursor[2] = (cursor[2]*alpha)/255 + r;
+ cursor[3] = 0xFF;
+ }
+ }
+
+ BitBlt(hdc, lprc->left, lprc->top, lprc->right - lprc->left, lprc->bottom - lprc->top, hdcTmp, 0, 0, SRCCOPY);
+ SelectObject(hdcTmp, hbmpTmp);
+ DeleteDC(hdcTmp);
+ }
+
+ SelectObject(hdcbmp, hbmpOld);
+
+ return 1;
+}
+
+// Draw a standard scrollbar arrow
+static int DrawScrollArrow(SCROLLBAR *sbar, HDC hdc, RECT *rect, UINT arrow, BOOL fMouseDown, BOOL fMouseOver, BOOL freeform)
+{
+ 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 = DrawFrameCtrl(hdc, rect, DFC_SCROLL, flags, fMouseOver, freeform);
+
+ return ret;
+}
+
+// Return the size in pixels for the specified scrollbar metric, for the specified scrollbar
+static int GetScrollMetric(SCROLLBAR *psb, int metric, DWORD scrollFlags)
+{
+ int type (psb ? psb->nBarType : SB_VERT);
+ switch (type)
+ {
+ case SB_HORZ:
+ {
+ switch (metric)
+ {
+ case SM_CXHORZSB:
+ if (SWS_USEFREEFORM & scrollFlags)
+ {
+ SkinBitmap button(L"wasabi.scrollbar.horizontal.left"); // we assume symmetry which isn't necessary safe
+ if (!button.isInvalid())
+ return WASABI_API_APP->getScaleX(button.getWidth());
+ }
+ return WASABI_API_APP->getScaleX(14); // classic skin fixes this at 14
+ default:
+ if (SWS_USEFREEFORM & scrollFlags)
+ {
+ SkinBitmap button(L"wasabi.scrollbar.horizontal.left"); // we assume symmetry which isn't necessary safe
+ if (!button.isInvalid())
+ return WASABI_API_APP->getScaleY(button.getHeight());
+ }
+ return WASABI_API_APP->getScaleY(14); // classic skin fixes this at 14
+ break;
+ }
+ }
+ break;
+
+ default: // case SB_VERT:
+ {
+ switch (metric)
+ {
+ case SM_CYVERTSB:
+ if (SWS_USEFREEFORM & scrollFlags)
+ {
+ SkinBitmap button(L"wasabi.scrollbar.vertical.left"); // we assume symmetry which isn't necessary safe
+ if (!button.isInvalid())
+ return WASABI_API_APP->getScaleY(button.getHeight());
+ }
+ return WASABI_API_APP->getScaleY(14); // classic skin fixes this at 14
+ default:
+ if (SWS_USEFREEFORM & scrollFlags)
+ {
+ SkinBitmap button(L"wasabi.scrollbar.vertical.left"); // we assume symmetry which isn't necessary safe
+ if (!button.isInvalid())
+ return WASABI_API_APP->getScaleX(button.getWidth());
+ }
+ return WASABI_API_APP->getScaleX(14); // classic skin fixes this at 14
+ break;
+ }
+ }
+ break;
+ }
+
+ /*
+ if ((SB_HORZ == psb->nBarType && metric == SM_CXHORZSB) || (SB_VERT == psb->nBarType && metric == SM_CYVERTSB))
+ return (psb->nArrowLength == SYSTEM_METRIC) * ((psb->nArrowLength < 0) ? -14 : 1);
+ else return psb->nArrowWidth * ((psb->nArrowWidth < 0) ? -14 : 1);
+ */
+}
+
+// Fill the specifed rectangle using a solid colour
+static void PaintRect(HDC hdc, RECT *rect, COLORREF color)
+{
+ COLORREF oldcol = SetBkColor(hdc, color);
+ ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, rect, L"", 0, 0);
+ SetBkColor(hdc, oldcol);
+}
+
+//
+// Set the minimum size, in pixels, that the thumb box will shrink to.
+//
+
+// 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
+static void DrawBlankButton(HDC hdc, const RECT *rect, UINT drawflag, int pushed, int vertical)
+{
+ HBITMAP hbmp, hbmpOld;
+ hbmp = WADlg_getBitmap();
+ if (!hbmp) return;
+
+ HDC hdcbmp = (HDC)MlStockObjects_Get(CACHED_DC);
+ 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);
+}
+
+
+// Calculate the screen coordinates of the area taken by
+// the horizontal scrollbar. Take into account the size
+// of the window borders
+static BOOL GetHScrollRect(SkinnedScrollWnd *pWnd, RECT *prc)
+{
+ if (pWnd->psbHorz->fScrollVisible)
+ {
+ GetClientRect(pWnd->hwnd, prc);
+ MapWindowPoints(pWnd->hwnd, HWND_DESKTOP, (POINT*)prc, 2);
+ prc->top = prc->bottom;
+ prc->bottom += GetScrollMetric(pWnd->psbHorz, SM_CYHORZSB, pWnd->scrollFlags);
+ }
+ else SetRect(prc, 0, 0, 0, 0);
+ return TRUE;
+}
+
+// Calculate the screen coordinates of the area taken by the
+// vertical scrollbar
+static BOOL GetVScrollRect(SkinnedScrollWnd *pWnd, RECT *prc)
+{
+ if (pWnd->psbVert->fScrollVisible)
+ {
+ GetClientRect(pWnd->hwnd, prc);
+ MapWindowPoints(pWnd->hwnd, HWND_DESKTOP, (POINT*)prc, 2);
+ if (SWS_LEFT & pWnd->scrollFlags)
+ {
+ prc->right = prc->left;
+ prc->left -= GetScrollMetric(pWnd->psbVert, SM_CXVERTSB, pWnd->scrollFlags);
+ }
+ else
+ {
+ prc->left = prc->right;
+ prc->right += GetScrollMetric(pWnd->psbVert, SM_CXVERTSB, pWnd->scrollFlags);
+ }
+ }
+ else SetRect(prc, 0, 0, 0, 0);
+
+
+ return TRUE;
+}
+
+// Depending on what type of scrollbar nBar refers to, call the
+// appropriate Get?ScrollRect function
+//
+static BOOL GetScrollRect(SkinnedScrollWnd *pWnd, UINT nBar, RECT *prc)
+{
+ if (nBar == SB_HORZ) return GetHScrollRect(pWnd, prc);
+ else if (nBar == SB_VERT) return GetVScrollRect(pWnd, prc);
+ 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, DWORD scrollFlags)
+{
+ 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, scrollFlags);
+
+ 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)
+ {
+ /*if (SWS_HIDEHSCROLL & scrollFlags)
+ thumbsize = MulDiv(si->nPage, workingsize, si->nMax);
+ else*/
+ thumbsize = MulDiv(si->nPage, workingsize, siMaxMin);
+
+ if (SWS_USEFREEFORM & scrollFlags)
+ {
+ SkinBitmap thumb((sbar->nBarType == SB_VERT)?L"wasabi.scrollbar.vertical.button":L"wasabi.scrollbar.horizontal.button");
+ if (!thumb.isInvalid())
+ thumbsize = (sbar->nBarType == SB_VERT)?thumb.getHeight():thumb.getWidth();
+ }
+
+ 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 (SWS_HIDEHSCROLL & scrollFlags)
+ {
+ thumbpos = (si->nPos == (si->nMax - si->nPage)) ?
+ (workingsize - thumbsize) : MulDiv(si->nPos, workingsize, si->nMax);
+ }*/
+
+ 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, DWORD scrollFlags)
+{
+ int thumbwidth, thumbpos;
+ int butwidth = GetScrollMetric(sbar, SM_SCROLL_LENGTH, scrollFlags);
+ 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, scrollFlags);
+
+ //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 (ESB_DISABLE_LEFT & sbar->fScrollFlags) ? HTSCROLL_NONE : HTSCROLL_LEFT;
+ }
+ //check for right button click
+ else if (x >= rect->right - butwidth && x < rect->right)
+ {
+ return (ESB_DISABLE_RIGHT & sbar->fScrollFlags) ? HTSCROLL_NONE : 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, DWORD scrollFlags)
+{
+ UINT r;
+
+ RotateRect(rect);
+ r = GetHorzScrollPortion(sb, hwnd, rect, y, x, scrollFlags);
+ RotateRect(rect);
+ return r;
+}
+
+static const wchar_t *GetThumbID(UINT barType, UINT scrollFlags, BOOL hover)
+{
+ if (barType == SB_VERT)
+ {
+ if (scrollFlags & CSBS_TRACKING)
+ return L"wasabi.scrollbar.vertical.button.pressed";
+ else if (hover)
+ return L"wasabi.scrollbar.vertical.button.hover";
+ else
+ return L"wasabi.scrollbar.vertical.button";
+ }
+ else
+ {
+ if (scrollFlags & CSBS_TRACKING)
+ return L"wasabi.scrollbar.horizontal.button.pressed";
+ else if (hover)
+ return L"wasabi.scrollbar.horizontal.button.hover";
+ else
+ return L"wasabi.scrollbar.horizontal.button";
+ }
+}
+
+static HBRUSH SetWindowPatternBrush(HWND hwnd, HDC hdc, UINT nBarType)
+{
+ RECT rw;
+ GetWindowRect(hwnd, &rw);
+ HWND hwndAncestor = GetAncestor(hwnd, GA_ROOT);
+ if (hwndAncestor) MapWindowPoints(HWND_DESKTOP, hwndAncestor, (POINT*)&rw, 2);
+ POINT ptOrg;
+ if (GetViewportOrgEx(hdc, &ptOrg)) OffsetRect(&rw, ptOrg.x, ptOrg.y);
+ if (nBarType == SB_VERT)
+ {
+ if (0 == (GetWindowLongPtrW(hwnd, GWL_EXSTYLE) & WS_EX_LEFTSCROLLBAR)) rw.left = rw.right;
+ }
+ else rw.top = rw.bottom;
+
+ SetBrushOrgEx(hdc, rw.left, rw.top, (POINT*)&rw);
+ return (HBRUSH)SelectObject(hdc, hbrChecked);
+}
+
+//
+// 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, UINT hoverFlags, DWORD scrollFlags)
+{
+ SCROLLINFO *si;
+ RECT ctrl, thumb;
+ RECT sbm;
+ int butwidth = GetScrollMetric(sb, SM_SCROLL_LENGTH, scrollFlags);
+ int scrollwidth = rect->right - rect->left;
+ int workingwidth = scrollwidth - butwidth * 2;
+ int thumbwidth = 0, thumbpos = 0;
+ int siMaxMin;
+
+ BOOL fMouseDownL = 0, fMouseOverL = (hoverFlags == HTSCROLL_LEFT);
+ BOOL fMouseDownR = 0, fMouseOverR = (hoverFlags == HTSCROLL_RIGHT);
+ BOOL fMouseOverThumb = (hoverFlags == HTSCROLL_THUMB);
+
+ COLORREF crCheck1 = GetSBForeColor();
+ COLORREF crCheck2 = GetSBBackColor();
+ COLORREF crInverse1 = WADlg_getColor(WADLG_SCROLLBAR_INV_FGCOLOR);
+ COLORREF crInverse2 = WADlg_getColor(WADLG_SCROLLBAR_INV_BGCOLOR);
+
+ UINT uDFCFlat = (CSBS_FLATSB & sb->fScrollFlags) ? DFCS_FLAT : 0;
+ UINT uDEFlat = (CSBS_FLATSB & sb->fScrollFlags) ? 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, scrollFlags);
+ if ((CSBS_TRACKING & sb->fScrollFlags) && trackThumbPos != -1)
+ {
+ thumbpos=trackThumbPos;
+ }
+
+ 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 ((0 == (DFCS_INACTIVE & uLeftButFlags) || 0 == (DFCS_INACTIVE & uRightButFlags)) &&
+ !(sb->fScrollFlags & CSBS_THUMBALWAYS) && !IsScrollInfoActive(si))
+ {
+ uLeftButFlags |= DFCS_INACTIVE;
+ uRightButFlags |= DFCS_INACTIVE;
+ }
+
+ if ((DFCS_INACTIVE & uLeftButFlags) && (DFCS_INACTIVE & uRightButFlags))
+ {
+ COLORREF rgbBk = WADlg_getColor(WADLG_WNDBG);
+ crCheck1 = BlendColors(crCheck1, rgbBk, INACTIVEBAR_ALPHA);
+ crCheck2 = BlendColors(crCheck2, rgbBk, INACTIVEBAR_ALPHA);
+ }
+
+ if (hwnd == hwndCurCoolSB)
+ {
+ fMouseDownL = (uDrawFlags == HTSCROLL_LEFT);
+ fMouseDownR = (uDrawFlags == HTSCROLL_RIGHT);
+ }
+
+ if (NULL == hbrChecked) //recreate pattern brush if needed
+ {
+ HBITMAP hbmp = CreateBitmap(8, 8, 1, 1, wCheckPat);
+ hbrChecked = CreatePatternBrush(hbmp);
+ DeleteObject(hbmp);
+ if (NULL == hbrChecked) return 0;
+ }
+
+
+
+ HBRUSH hbrOld = NULL;
+
+ COLORREF rgbFgOld, rgbBkOld;
+ rgbFgOld = SetTextColor(hdc, crCheck1);
+ rgbBkOld = SetBkColor(hdc, crCheck2);
+
+ //
+ // Draw the scrollbar now
+ //
+ if (scrollwidth > butwidth*2)
+ {
+ DCCanvas canvas(hdc);
+ if (SWS_USEFREEFORM & scrollFlags)
+ {
+ CopyRect(&ctrl, rect);
+ RotateRect0(sb, &ctrl);
+ RenderBaseTexture(&canvas, &ctrl, hwnd);
+ }
+
+ //LEFT ARROW
+ SetRect(&ctrl, rect->left, rect->top, rect->left + butwidth, rect->bottom);
+
+ RotateRect0(sb, &ctrl);
+
+ DrawScrollArrow(sb, hdc, &ctrl, uLeftButFlags, fMouseDownL, fMouseOverL, (SWS_USEFREEFORM & scrollFlags));
+
+ 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))
+ {
+ SkinBitmap *bg = (scrollBitmaps && (SWS_USEFREEFORM & scrollFlags)) ?
+ ((sb->nBarType== SB_VERT) ? scrollBitmaps->v_mid.getBitmap(): scrollBitmaps->h_mid.getBitmap())
+ : 0;
+
+ if ((SWS_USEFREEFORM & scrollFlags) && bg && !bg->isInvalid())
+ {
+ SetRect(&sbm, rect->left + butwidth, rect->top, rect->right-butwidth, rect->bottom);
+ RotateRect0(sb, &sbm);
+
+ bg->stretchToRectAlpha(&canvas, &sbm);
+
+ SkinBitmap thumbBitmap(GetThumbID(sb->nBarType, sb->fScrollFlags, fMouseOverThumb));
+ SetRect(&sbm, thumbpos, rect->top, thumbpos+thumbwidth, rect->bottom);
+ RotateRect0(sb, &sbm);
+ if (!thumbBitmap.isInvalid())
+ thumbBitmap.stretchToRectAlpha(&canvas, &sbm);
+ else
+ DrawBlankButton(hdc, &sbm, uDEFlat, (CSBS_TRACKING & sb->fScrollFlags), sb->nBarType == SB_VERT);
+ }
+ else
+ {
+ //Draw the scrollbar margin above the thumb
+ SetRect(&sbm, rect->left + butwidth, rect->top, thumbpos, rect->bottom);
+
+ RotateRect0(sb, &sbm);
+
+ if (HTSCROLL_PAGELEFT == uDrawFlags)
+ {
+ SetTextColor(hdc, crInverse1);
+ SetBkColor(hdc, crInverse2);
+ }
+
+ if (GetTextColor(hdc) == GetBkColor(hdc)) ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &sbm, NULL, 0, NULL);
+ else
+ {
+ if (NULL == hbrOld) hbrOld = SetWindowPatternBrush(hwnd, hdc, sb->nBarType);
+ PatBlt(hdc, sbm.left, sbm.top, sbm.right - sbm.left, sbm.bottom - sbm.top, PATCOPY);
+ }
+
+ if (HTSCROLL_PAGELEFT == uDrawFlags)
+ {
+ SetTextColor(hdc, crCheck1);
+ SetBkColor(hdc, crCheck2);
+ }
+
+ RotateRect0(sb, &sbm);
+
+ //Draw the margin below the thumb
+ sbm.left = thumbpos + thumbwidth;
+ sbm.right = rect->right - butwidth;
+
+ RotateRect0(sb, &sbm);
+
+ if (HTSCROLL_PAGERIGHT == uDrawFlags)
+ {
+ SetTextColor(hdc, crInverse1);
+ SetBkColor(hdc, crInverse2);
+ }
+
+ if (GetTextColor(hdc) == GetBkColor(hdc)) ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &sbm, NULL, 0, NULL);
+ else
+ {
+ if (NULL == hbrOld) hbrOld = SetWindowPatternBrush(hwnd, hdc, sb->nBarType);
+ PatBlt(hdc, sbm.left, sbm.top, sbm.right - sbm.left, sbm.bottom - sbm.top, PATCOPY);
+ }
+
+ if (HTSCROLL_PAGERIGHT == uDrawFlags)
+ {
+ SetTextColor(hdc, crCheck1);
+ SetBkColor(hdc, crCheck2);
+ }
+
+ RotateRect0(sb, &sbm);
+
+ //Draw the THUMB finally
+ SetRect(&thumb, thumbpos, rect->top, thumbpos + thumbwidth, rect->bottom);
+
+ RotateRect0(sb, &thumb);
+
+ DrawBlankButton(hdc, &thumb, uDEFlat, (CSBS_TRACKING & sb->fScrollFlags), 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);
+
+ 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);
+
+ PaintRect(hdc, &ctrl, GetSysColor(COLOR_SCROLLBAR));
+
+ RotateRect0(sb, &ctrl);
+ }
+ //otherwise, paint a blank if the thumb doesn't fit in
+ else
+ {
+ RotateRect0(sb, &ctrl);
+ BOOL classic(TRUE);
+ if (SWS_USEFREEFORM & scrollFlags)
+ {
+ SkinBitmap background(sb->nBarType== SB_VERT?L"wasabi.scrollbar.vertical.background.middle":L"wasabi.scrollbar.horizontal.background.middle");
+ if (!background.isInvalid())
+ {
+ background.stretchToRectAlpha(&canvas, &ctrl,
+ ((DFCS_INACTIVE & uLeftButFlags) && (DFCS_INACTIVE & uRightButFlags)) ? INACTIVEBAR_ALPHA : 255);
+ classic = FALSE;
+ }
+ }
+
+ if (classic)
+ {
+ if (crCheck1 == crCheck2) ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &ctrl, NULL, 0, NULL);
+ else
+ {
+ if (NULL == hbrOld) hbrOld = SetWindowPatternBrush(hwnd, hdc, sb->nBarType);
+ PatBlt(hdc, ctrl.left, ctrl.top, ctrl.right - ctrl.left, ctrl.bottom - ctrl.top, PATCOPY);
+ }
+ }
+
+
+ RotateRect0(sb, &ctrl);
+ }
+ }
+
+ //RIGHT ARROW
+ SetRect(&ctrl, rect->right - butwidth, rect->top, rect->right, rect->bottom);
+
+ RotateRect0(sb, &ctrl);
+
+ DrawScrollArrow(sb, hdc, &ctrl, uRightButFlags, fMouseDownR, fMouseOverR, (SWS_USEFREEFORM & scrollFlags));
+
+ 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);
+ DrawScrollArrow(sb, hdc, &ctrl, uLeftButFlags, fMouseDownL, fMouseOverL, (SWS_USEFREEFORM & scrollFlags));
+ RotateRect0(sb, &ctrl);
+
+ //RIGHT ARROW
+ OffsetRect(&ctrl, scrollwidth - butwidth, 0);
+
+ RotateRect0(sb, &ctrl);
+ DrawScrollArrow(sb, hdc, &ctrl, uRightButFlags, fMouseDownR, fMouseOverR, (SWS_USEFREEFORM & scrollFlags));
+ 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);
+ BOOL classic(TRUE);
+
+ if (SWS_USEFREEFORM & scrollFlags)
+ {
+ SkinBitmap background(sb->nBarType== SB_VERT?L"wasabi.scrollbar.vertical.background.middle":L"wasabi.scrollbar.horizontal.background.middle");
+ if (!background.isInvalid())
+ {
+ DCCanvas canvas(hdc);
+ RenderBaseTexture(&canvas, &ctrl, hwnd);
+ background.stretchToRectAlpha(&canvas, &ctrl,
+ ((DFCS_INACTIVE & uLeftButFlags) && (DFCS_INACTIVE & uRightButFlags)) ? INACTIVEBAR_ALPHA : 255);
+ classic = FALSE;
+ }
+ }
+
+ if (classic)
+ {
+ if (crCheck1 == crCheck2) ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &ctrl, NULL, 0, NULL);
+ else
+ {
+ if (NULL == hbrOld) hbrOld = SetWindowPatternBrush(hwnd, hdc, sb->nBarType);
+ PatBlt(hdc, ctrl.left, ctrl.top, ctrl.right - ctrl.left, ctrl.bottom - ctrl.top, PATCOPY);
+ }
+ }
+
+ RotateRect0(sb, &ctrl);
+ }
+
+ }
+
+ SetBkColor(hdc, rgbBkOld);
+ SetTextColor(hdc, rgbFgOld);
+ if (hbrOld)
+ {
+ SelectObject(hdc, hbrOld);
+ SetBrushOrgEx(hdc, 0, 0, NULL);
+ }
+ return 0;
+}
+
+//
+// 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, UINT hoverFlags, DWORD scrollFlags)
+{
+ LRESULT ret;
+ RECT rc;
+
+ rc = *rect;
+ RotateRect(&rc);
+ ret = NCDrawHScrollbar(sb, hwnd, hdc, &rc, uDrawFlags, hoverFlags, scrollFlags);
+ 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, UINT hoverFlags, DWORD scrollFlags)
+{
+ if (sb->nBarType == SB_HORZ)
+ return NCDrawHScrollbar(sb, hwnd, hdc, rect, uDrawFlags, hoverFlags, scrollFlags);
+ else
+ return NCDrawVScrollbar(sb, hwnd, hdc, rect, uDrawFlags, hoverFlags, scrollFlags);
+}
+
+
+
+void SkinnedScrollWnd::PaintNonClient(HDC hdc)
+{
+ RECT winrect, rcH, rcV;
+ BOOL drawH = FALSE, drawV = FALSE;
+
+ if (!psbHorz->fScrollVisible && !psbVert->fScrollVisible)
+ {
+ DrawBorder(hdc);
+ return;
+ }
+
+ if (0 == (SWS_UPDATEFRAME & scrollFlags))
+ {
+ HWND hwndActive;
+ hwndActive = GetActiveWindow();
+ if (hwndActive != hwnd && !IsChild(hwndActive, hwnd)) scrollFlags |= SWS_UPDATEFRAME;
+ }
+
+ GetWindowRect(hwnd, &winrect);
+
+
+ if (psbHorz->fScrollVisible)
+ {
+ GetHScrollRect(this, &rcH);
+ OffsetRect(&rcH, -winrect.left, -winrect.top);
+ if (rcH.right > rcH.left && rcH.bottom > rcH.top && RectVisible(hdc, &rcH)) drawH = TRUE;
+ }
+
+ if (psbVert->fScrollVisible)
+ {
+ GetVScrollRect(this, &rcV);
+ OffsetRect(&rcV, -winrect.left, -winrect.top);
+
+ if (rcV.right > rcV.left && rcV.bottom > rcV.top && RectVisible(hdc, &rcV)) drawV = TRUE;
+ }
+ DrawBorder(hdc);
+
+ POINT ptOrg;
+ GetViewportOrgEx(hdc, &ptOrg);
+
+ if (drawH)
+ {
+ UINT fDraw, fHover;
+ if (uCurrentScrollbar == SB_HORZ) { fDraw = uScrollTimerPortion; fHover = HTSCROLL_NONE; }
+ else
+ {
+ fDraw = HTSCROLL_NONE;
+ fHover = (NULL != psbHorz && 0 != (CSBS_HOVERING & psbHorz->fScrollFlags)) ? scrollPortionHover : HTSCROLL_NONE;
+ }
+
+ if (SWS_USEFREEFORM & scrollFlags)
+ {
+ DCBltCanvas buffer;
+ buffer.cloneDC(hdc, &rcH);
+ NCDrawHScrollbar(psbHorz, hwnd, buffer.getHDC(), &rcH, fDraw, fHover, scrollFlags);
+ }
+ else
+ {
+ SetViewportOrgEx(hdc, ptOrg.x + rcH.left, ptOrg.y + rcH.top, NULL);
+ OffsetRect(&rcH, -rcH.left, -rcH.top);
+ NCDrawHScrollbar(psbHorz, hwnd, hdc, &rcH, fDraw, fHover, scrollFlags);
+ SetViewportOrgEx(hdc, ptOrg.x, ptOrg.y, NULL);
+ }
+ }
+
+ if (drawV)
+ {
+ UINT fDraw, fHover;
+ if (uCurrentScrollbar == SB_VERT) { fDraw = uScrollTimerPortion; fHover = HTSCROLL_NONE; }
+ else
+ {
+ fDraw = HTSCROLL_NONE;
+ fHover = (NULL != psbVert && 0 != (CSBS_HOVERING & psbVert->fScrollFlags)) ? scrollPortionHover : HTSCROLL_NONE;
+ }
+
+ if (SWS_USEFREEFORM & scrollFlags)
+ {
+ DCBltCanvas buffer;
+ buffer.cloneDC(hdc, &rcV);
+ NCDrawVScrollbar(psbVert, hwnd, buffer.getHDC(), &rcV, fDraw, fHover, scrollFlags);
+
+ }
+ else
+ {
+ SetViewportOrgEx(hdc, ptOrg.x + rcV.left, ptOrg.y + rcV.top, NULL);
+ OffsetRect(&rcV, -rcV.left, -rcV.top);
+ NCDrawVScrollbar(psbVert, hwnd, hdc, &rcV, fDraw, fHover, scrollFlags);
+ SetViewportOrgEx(hdc, ptOrg.x, ptOrg.y, NULL);
+ }
+
+ }
+
+ SetViewportOrgEx(hdc, ptOrg.x, ptOrg.y, NULL);
+
+ // DRAW THE DEAD AREA
+ // only do this if the horizontal and vertical bars are visible
+ if (psbHorz->fScrollVisible && psbVert->fScrollVisible)
+ {
+ GetClientRect(hwnd, &rcH);
+ MapWindowPoints(hwnd, HWND_DESKTOP, (POINT*)&rcH, 2);
+ OffsetRect(&rcH, -winrect.left, -winrect.top);
+
+ rcH.top = rcH.bottom;
+ rcH.bottom += GetScrollMetric(psbHorz, SM_CYHORZSB, scrollFlags);
+
+ if (SWS_LEFT & scrollFlags)
+ {
+ rcH.right = rcH.left;
+ rcH.left -= GetScrollMetric(psbVert, SM_CXVERTSB, scrollFlags);
+ }
+ else
+ {
+ rcH.left = rcH.right;
+ rcH.right += GetScrollMetric(psbVert, SM_CXVERTSB, scrollFlags);
+ }
+
+ if (RectVisible(hdc, &rcH))
+ {
+
+ PaintRect(hdc, &rcH, WADlg_getColor(WADLG_SCROLLBAR_DEADAREA_COLOR));
+ }
+ }
+
+
+}
+
+void SkinnedScrollWnd::OnNcPaint(HRGN rgnUpdate)
+{
+ UINT flags = DCX_PARENTCLIP | DCX_CACHE | DCX_WINDOW | DCX_CLIPSIBLINGS |
+ DCX_INTERSECTUPDATE | DCX_VALIDATE;
+
+ HDC hdc = GetDCEx(hwnd, ((HRGN)NULLREGION != rgnUpdate) ? rgnUpdate : NULL, flags);
+
+
+ if (NULL == hdc)
+ {
+ return;
+ }
+
+
+ PaintNonClient(hdc);
+
+
+ ReleaseDC(hwnd, hdc);
+}
+
+//
+// Need to detect if we have clicked in the scrollbar region or not
+//
+INT SkinnedScrollWnd::OnNcHitTest(POINTS pts)
+{
+ RECT rc;
+
+ INT r = __super::OnNcHitTest(pts);
+ if (r == HTTRANSPARENT)
+ {
+
+
+ return r;
+ }
+
+ if (psbHorz->fScrollVisible && GetHScrollRect(this, &rc) &&
+ pts.x >= rc.left && pts.x <= rc.right && pts.y >= rc.top && pts.y <= rc.bottom) return HTHSCROLL;
+ if (psbVert->fScrollVisible && GetVScrollRect(this, &rc) &&
+ pts.x >= rc.left && pts.x <= rc.right && pts.y >= rc.top && pts.y <= rc.bottom) return HTVSCROLL;
+
+ return r;
+}
+
+//
+// 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, DWORD scrollFlags)
+{
+ 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, scrollFlags);
+}
+
+//
+// Just call the horizontal version, with adjusted coordinates
+//
+static UINT GetVertPortion(SCROLLBAR *sb, HWND hwnd, RECT *rect, int x, int y, DWORD scrollFlags)
+{
+ UINT ret;
+ RotateRect(rect);
+ ret = GetHorzPortion(sb, hwnd, rect, y, x, scrollFlags);
+ RotateRect(rect);
+ return ret;
+}
+
+//
+// Wrapper function for GetHorzPortion and GetVertPortion
+//
+static UINT GetPortion(SCROLLBAR *sb, HWND hwnd, RECT *rect, int x, int y, DWORD scrollFlags)
+{
+ if (sb->nBarType == SB_HORZ) return GetHorzPortion(sb, hwnd, rect, x, y, scrollFlags);
+ else if (sb->nBarType == SB_VERT) return GetVertPortion(sb, hwnd, rect, x, y, scrollFlags);
+ 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 (CSBS_BTNVISBEFORE & sb->fScrollFlags) rect->left += sb->nButSizeBefore;
+ if (CSBS_BTNVISAFTER & sb->fScrollFlags) 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 (CSBS_BTNVISBEFORE & sb->fScrollFlags) rect->top += sb->nButSizeBefore;
+ if (CSBS_BTNVISAFTER & sb->fScrollFlags) 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, DWORD scrollFlags)
+{
+ 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
+//
+void SkinnedScrollWnd::OnNcLButtonDown(UINT nHitTest, POINTS pts)
+{
+ RECT rect, winrect;
+ SCROLLBAR *psb;
+
+ hwndCurCoolSB = hwnd;
+
+ //
+ // HORIZONTAL SCROLLBAR PROCESSING
+ //
+ if (HTHSCROLL == nHitTest)
+ {
+ psb = psbHorz;
+ uScrollTimerMsg = WM_HSCROLL;
+ uCurrentScrollbar = SB_HORZ;
+ //get the total area of the normal Horz scrollbar area
+ GetHScrollRect(this, &rect);
+ uCurrentScrollPortion = GetHorzPortion(psbHorz, hwnd, &rect, pts.x, pts.y, scrollFlags);
+ }
+ //
+ // VERTICAL SCROLLBAR PROCESSING
+ //
+ else if (HTVSCROLL== nHitTest)
+ {
+ psb = psbVert;
+ uScrollTimerMsg = WM_VSCROLL;
+ uCurrentScrollbar = SB_VERT;
+ //get the total area of the normal Horz scrollbar area
+ GetVScrollRect(this, &rect);
+ uCurrentScrollPortion = GetVertPortion(psbVert, hwnd, &rect, pts.x, pts.y, scrollFlags);
+ }
+ //
+ // NORMAL PROCESSING
+ //
+ else
+ {
+ uCurrentScrollPortion = HTSCROLL_NONE;
+ __super::WindowProc(WM_NCLBUTTONDOWN, (WPARAM)nHitTest, *(LPARAM*)&pts);
+ return;
+ }
+
+ //
+ // 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(psb)) return;
+
+ GetRealScrollRect(psb, &rect, scrollFlags);
+ RotateRect0(psb, &rect);
+ CalcThumbSize(psb, &rect, &nThumbSize, &nThumbPos, scrollFlags);
+ RotateRect0(psb, &rect);
+
+ //remember the bounding rectangle of the scrollbar work area
+ rcThumbBounds = rect;
+
+ trackThumbPos=-1;
+ psb->fScrollFlags |= CSBS_TRACKING;
+ psb->scrollInfo.nTrackPos = psb->scrollInfo.nPos;
+
+ if (nHitTest == HTVSCROLL) nThumbMouseOffset = pts.y - nThumbPos;
+ else nThumbMouseOffset = pts.x - nThumbPos;
+
+ nLastPos = psb->scrollInfo.nPos;
+ nThumbPos0 = nThumbPos;
+
+ SCROLLINFO info;
+ info.cbSize = sizeof(SCROLLINFO);
+ info.fMask = SIF_POS;
+ info.nPos = nLastPos;
+
+ SetScrollInfo(hwnd, psb->nBarType, &info, FALSE);
+
+ SendScrollMessage(hwnd, uScrollTimerMsg, SB_THUMBTRACK, nLastPos);
+ //if(sb->fFlatScrollbar)
+ //{
+ GetWindowRect(hwnd, &winrect);
+ OffsetRect(&rect, -winrect.left, -winrect.top);
+ InvalidateNC(InvalidateFlag_Normal, uCurrentScrollbar);
+ //}
+
+ break;
+
+ //Any part of the scrollbar
+ case HTSCROLL_LEFT:
+ if (psb->fScrollFlags & ESB_DISABLE_LEFT) return;
+ goto target1;
+
+ case HTSCROLL_RIGHT:
+ if (psb->fScrollFlags & ESB_DISABLE_RIGHT) return;
+ goto target1;
+
+
+ case HTSCROLL_PAGELEFT:
+ case HTSCROLL_PAGERIGHT:
+
+target1:
+
+ //if the scrollbar is disabled, then do no further processing
+ if (!IsScrollbarActive(psb))
+ break;
+
+ //ajust the horizontal rectangle to NOT include
+ //any inserted buttons
+ GetRealScrollRect(psb, &rect, scrollFlags);
+
+ 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(psb, hwnd, &rect, pts.x, pts.y, scrollFlags);
+ else
+ uScrollTimerPortion = GetVertScrollPortion(psb, hwnd, &rect, pts.x, pts.y, scrollFlags);
+
+ GetWindowRect(hwnd, &winrect);
+ OffsetRect(&rect, -winrect.left, -winrect.top);
+
+
+ //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;
+
+ InvalidateNC(InvalidateFlag_Normal, uCurrentScrollbar);
+
+ //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);
+ UpdateScrollBars(FALSE);
+ break;
+ default:
+ __super::WindowProc(WM_NCLBUTTONDOWN, (WPARAM)nHitTest, *(LPARAM*)&pts);
+ return;
+
+ }
+
+ if ((0 == (SWS_COMBOLBOX & scrollFlags)) && hwnd != GetCapture())
+ {
+ ignoreCaptureChange = TRUE;
+ SetCapture(hwnd);
+ ignoreCaptureChange = FALSE;
+ captureSet = TRUE;
+
+ }
+}
+
+//
+// Left button released
+//
+void SkinnedScrollWnd::Emulate_LeftButtonUp(UINT nFlags, POINTS pts, BOOL forwardMessage)
+{
+ //current scrollportion is the button that we clicked down on
+ if (uCurrentScrollPortion != HTSCROLL_NONE)
+ {
+ RECT rect;
+ //UINT thisportion;
+ POINT pt;
+ RECT winrect;
+
+ SCROLLBAR *psb;
+
+ if (captureSet && (0 == (SWS_COMBOLBOX & scrollFlags)) && hwnd == GetCapture())
+ {
+ ignoreCaptureChange = TRUE;
+ ReleaseCapture();
+ ignoreCaptureChange = FALSE;
+ }
+ captureSet = FALSE;
+
+ GetWindowRect(hwnd, &winrect);
+ POINTSTOPOINT(pt, pts);
+
+ //emulate the mouse input on a scrollbar here...
+ if (SB_VERT == uCurrentScrollbar)
+ {
+ //get the total area of the normal Horz scrollbar area
+ psb = psbVert;
+ GetVScrollRect(this, &rect);
+ }
+ else
+ {
+ //get the total area of the normal Horz scrollbar area
+ psb = psbHorz;
+ GetHScrollRect(this, &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:
+ UpdateScrollBars(FALSE);
+
+ //In case we were thumb tracking, make sure we stop NOW
+ if (CSBS_TRACKING & psb->fScrollFlags)
+ {
+ SCROLLINFO info;
+ info.cbSize = sizeof(SCROLLINFO);
+ info.fMask = SIF_POS;
+ info.nPos = nLastPos;
+
+ SetScrollInfo(hwnd, psb->nBarType, &info, FALSE);
+ SendScrollMessage(hwnd, uScrollTimerMsg, SB_THUMBPOSITION, nLastPos);
+ psb->fScrollFlags &= ~CSBS_TRACKING;
+ }
+
+ //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(psb, &rect, scrollFlags);
+ OffsetRect(&rect, -winrect.left, -winrect.top);
+ InvalidateNC(InvalidateFlag_Normal, uCurrentScrollbar);
+ break;
+ }
+
+ //reset our state to default
+ uCurrentScrollPortion = HTSCROLL_NONE;
+ uScrollTimerPortion = HTSCROLL_NONE;
+ uScrollTimerId = 0;
+
+ uScrollTimerMsg = 0;
+ uCurrentScrollbar = COOLSB_NONE;
+
+ return;
+ }
+ else
+ {
+
+ /*
+ // Can't remember why I did this!
+ if(GetCapture() == hwnd)
+ {
+ ReleaseCapture();
+ }*/
+ }
+
+ //sw->update();
+
+ if (FALSE != forwardMessage)
+ {
+ __super::WindowProc(WM_LBUTTONUP, (WPARAM)nFlags, *(LPARAM*)&pts);
+ }
+}
+void SkinnedScrollWnd::OnLButtonUp(UINT nFlags, POINTS pts)
+{
+ Emulate_LeftButtonUp(nFlags, pts, TRUE);
+}
+
+static int
+ListView_ScrollWindow(HWND hwnd, int dy)
+{
+ RECT rect;
+
+ if (0 == dy)
+ return NULLREGION;
+
+ if (FALSE == GetClientRect(hwnd, &rect))
+ return ERROR;
+
+ if (0 == (LVS_NOCOLUMNHEADER & GetWindowLongPtrW(hwnd, GWL_STYLE)))
+ {
+ HWND headerWindow;
+ headerWindow = (HWND)SendMessageW(hwnd, LVM_GETHEADER, 0, 0L);
+ if (NULL != headerWindow &&
+ 0 != (WS_VISIBLE & GetWindowLongPtrW(headerWindow, GWL_STYLE)))
+ {
+ HDLAYOUT headerLayout;
+ WINDOWPOS headerPos;
+
+ headerLayout.prc = &rect;
+ headerLayout.pwpos = &headerPos;
+ SendMessageW(headerWindow, HDM_LAYOUT, 0, (LPARAM)&headerLayout);
+ }
+ }
+
+ return ScrollWindowEx(hwnd, 0, dy, &rect, &rect, NULL, NULL, SW_INVALIDATE);
+}
+
+static BOOL ListView_ScrollReportModeVert(HWND hwnd, INT linesVert, BOOL horzBarHidden)
+{
+ int max, pos, page;
+ int itemHeight, prevPos, dy;
+ RECT rect;
+ unsigned long windowStyle;
+
+ if (0 == linesVert)
+ return TRUE;
+
+ windowStyle = GetWindowLongPtrW(hwnd, GWL_STYLE);
+
+ pos = (int)SendMessageW(hwnd, LVM_GETTOPINDEX, 0, 0L);
+ max = (int)SendMessageW(hwnd, LVM_GETITEMCOUNT, 0, 0L);
+ page = (int)SendMessageW(hwnd, LVM_GETCOUNTPERPAGE, 0, 0L);
+
+ if (FALSE == horzBarHidden)
+ max++;
+
+ if ((linesVert < 0 && pos <= 0) ||
+ (linesVert > 0 && (pos + page) >= max))
+ {
+ return TRUE;
+ }
+
+ if (linesVert < 0 && (pos + linesVert) < 0)
+ linesVert = -pos;
+ else if (linesVert > 0 && (pos + page + linesVert) > max)
+ linesVert = max - (page + pos);
+
+ rect.left = LVIR_BOUNDS;
+ if (!SendMessageW(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect))
+ return FALSE;
+
+ if (rect.top < 0)
+ OffsetRect(&rect, 0, -rect.top);
+
+ itemHeight = rect.bottom - rect.top;
+
+ if (0 != (WS_VISIBLE & windowStyle))
+ SetWindowLongPtrW(hwnd, GWL_STYLE, windowStyle & ~WS_VISIBLE);
+
+ dy = linesVert * itemHeight;
+ SendMessageW(hwnd, LVM_SCROLL, 0, dy);
+
+ if (0 == (WS_VISIBLE & windowStyle))
+ return TRUE;
+
+ SetWindowLongPtrW(hwnd, GWL_STYLE, windowStyle);
+
+ prevPos = pos;
+ pos = (int)SendMessageW(hwnd, LVM_GETTOPINDEX, 0, 0L);
+ linesVert = pos - prevPos;
+
+ dy = linesVert * itemHeight;
+
+ if (ERROR == ListView_ScrollWindow(hwnd, -dy))
+ InvalidateRect(hwnd, NULL, FALSE);
+
+ return TRUE;
+}
+
+static BOOL
+ListView_ScrollReportModeVertPx(HWND hwnd, int dy, BOOL horzBarHidden)
+{
+ int itemHeight, lines;
+ RECT rect;
+ unsigned long windowStyle;
+
+ if (0 == dy)
+ return TRUE;
+
+ windowStyle = GetWindowLongPtrW(hwnd, GWL_STYLE);
+
+ rect.left = LVIR_BOUNDS;
+ if (!SendMessageW(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect))
+ return FALSE;
+
+ if (rect.top < 0)
+ OffsetRect(&rect, 0, -rect.top);
+
+ itemHeight = rect.bottom - rect.top;
+
+
+ lines = dy / itemHeight;
+ if (0 != lines)
+ {
+ if (0 != (WS_VISIBLE & windowStyle))
+ SetWindowLongPtrW(hwnd, GWL_STYLE, windowStyle & ~WS_VISIBLE);
+
+ SendMessageW(hwnd, LVM_SCROLL, 0, lines);
+
+ if (0 != (WS_VISIBLE & windowStyle))
+ {
+ windowStyle = GetWindowLongPtrW(hwnd, GWL_STYLE);
+ windowStyle |= WS_VISIBLE;
+ SetWindowLongPtrW(hwnd, GWL_STYLE, windowStyle);
+ }
+ }
+
+ if (0 != (WS_VISIBLE & windowStyle))
+ {
+ if (ERROR == ListView_ScrollWindow(hwnd, -dy))
+ InvalidateRect(hwnd, NULL, FALSE);
+ }
+
+ return TRUE;
+}
+
+//
+// This function is called whenever the mouse is moved and
+// we are dragging the scrollbar thumb about.
+//
+static void ThumbTrack(SCROLLBAR *sbar, HWND hwnd, POINTS pts, UINT scrollFlags)
+{
+ POINT pt;
+ RECT rc, winrect, rc2;
+ int thumbpos = nThumbPos;
+ //int thumbDelta;
+ int pos;
+ int siMaxMin = 0;
+ //UINT flatflag = (CSBS_FLATSB & sbar->fScrollFlags) ? BF_FLAT : 0;
+
+ SCROLLINFO *si;
+ si = &sbar->scrollInfo;
+
+ POINTSTOPOINT(pt, pts);
+ MapWindowPoints(hwnd, HWND_DESKTOP, &pt, 1);
+
+ if (SB_VERT == sbar->nBarType)
+ {
+ LONG t;
+ t= pt.x; pt.x = pt.y; pt.y = t;
+ RotateRect(&rcThumbBounds);
+ }
+
+ //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);
+
+ int cxH = GetScrollMetric(sbar, SM_CXHORZSB, scrollFlags);
+
+ rc.left += cxH;
+ rc.right -= cxH;
+
+ //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;
+ }
+
+ GetClientRect(hwnd, &winrect);
+
+ MapWindowPoints(hwnd, HWND_DESKTOP, (POINT*)&winrect, 2);
+
+ RotateRect0(sbar, &winrect);
+
+ OffsetRect(&rc, -winrect.left, -winrect.top);
+ thumbpos -= winrect.left;
+
+ /*if (-1 == trackThumbPos)
+ thumbDelta = thumbpos - rc.left;
+ else
+ thumbDelta = thumbpos - trackThumbPos;*/
+
+ trackThumbPos = thumbpos;
+
+ //post a SB_TRACKPOS message!!!
+ siMaxMin = si->nMax - si->nMin;
+ pos = (siMaxMin > 0) ? MulDiv(thumbpos - rc.left, siMaxMin - si->nPage + 1, rc.right - rc.left - nThumbSize) : (thumbpos - rc.left);
+
+ if (si->nPage == 0)
+ pos = 0; // this supposed to protect from moving on empty scrollbar
+
+ if (pos != nLastPos)
+ {
+ if (SWS_LISTVIEW & scrollFlags) // list view specific
+ {
+ // 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 dx = pos - info.nTrackPos;
+ if (LVS_LIST == (LVS_TYPEMASK & GetWindowLongPtrW(hwnd, GWL_STYLE)))
+ {
+ INT cw = (INT)(INT_PTR)SendMessageW(hwnd, LVM_GETCOLUMNWIDTH, 0, 0L);
+ dx = dx * cw;
+ }
+ SendMessageW(hwnd, LVM_SCROLL, dx, 0);
+ }
+ }
+ else if (sbar->nBarType == SB_VERT)
+ {
+ SCROLLINFO info;
+ info.cbSize = sizeof(SCROLLINFO);
+ info.fMask = SIF_TRACKPOS;
+ if (GetScrollInfo(hwnd, SB_VERT, &info) && pos != info.nTrackPos)
+ {
+ INT dy = pos - info.nTrackPos;
+ if (LVS_REPORT == (LVS_TYPEMASK & GetWindowLongPtrW(hwnd, GWL_STYLE)))
+ {
+ ListView_ScrollReportModeVert(hwnd, dy, (0 != (SWS_HIDEHSCROLL & scrollFlags)));
+ }
+ else
+ {
+ SendMessageW(hwnd, LVM_SCROLL, 0, dy);
+ }
+ }
+ }
+ }
+ else if ((SWS_TREEVIEW & scrollFlags) &&
+ SB_VERT == sbar->nBarType &&
+ ABS(nLastPos - pos) < 2)
+ {
+ INT i, cmd;
+ i = nLastPos - pos;
+ cmd = (i < 0) ? SB_LINEDOWN : SB_LINEUP;
+ if (i < 0) i = -i;
+ while (i--)
+ {
+ SendMessageW(hwnd, WM_VSCROLL, cmd, 0L);
+ }
+ }
+ else
+ {
+ si->nTrackPos = pos;
+ SCROLLINFO info;
+ info.cbSize = sizeof(SCROLLINFO);
+ info.fMask = SIF_TRACKPOS|SIF_POS;
+ info.nTrackPos = pos;
+ info.nPos = pos;
+
+ SetScrollInfo(hwnd, sbar->nBarType, &info, FALSE);
+ SendScrollMessage(hwnd, uScrollTimerMsg, SB_THUMBTRACK, pos);
+ }
+ }
+
+ nLastPos = pos;
+
+ if (SB_VERT == sbar->nBarType) RotateRect(&rcThumbBounds);
+}
+
+//
+// remember to rotate the thumb bounds rectangle!!
+//
+
+//
+// Called when we have set the capture from the NCLButtonDown(...)
+//
+void SkinnedScrollWnd::OnMouseMove(UINT nFlags, POINTS pts)
+{
+ RECT rect;
+ //static UINT lastbutton = 0;
+ RECT winrect;
+ //UINT buttonIdx = 0;
+ SCROLLBAR *psb;
+
+ if (nFlags)
+ {
+ if (MK_LBUTTON & nFlags)
+ {
+ UpdateScrollBars(TRUE);
+ }
+ }
+ psb = (uCurrentScrollbar == SB_VERT) ? psbVert : psbHorz;
+ if (CSBS_TRACKING & psb->fScrollFlags)
+ {
+ ThumbTrack(psb, hwnd, pts, scrollFlags);
+ InvalidateNC(InvalidateFlag_Normal, uCurrentScrollbar);
+ return;
+ }
+ if (uCurrentScrollPortion == HTSCROLL_NONE)
+ {
+ __super::WindowProc(WM_MOUSEMOVE, (WPARAM)nFlags, *(LPARAM*)&pts);
+ return;
+ }
+ else
+ {
+ static UINT lastportion = 0;
+ POINT pt;
+
+ POINTSTOPOINT(pt, pts);
+
+ MapWindowPoints(hwnd, HWND_DESKTOP, &pt, 1);
+
+ GetWindowRect(hwnd, &winrect);
+
+ //get the total area of the normal scrollbar area
+ GetScrollRect(this, psb->nBarType, &rect);
+
+ //see if we clicked in the inserted buttons / normal scrollbar
+ //thisportion = GetPortion(sb, hwnd, &rect, LOWORD(lParam), HIWORD(lParam));
+ UINT thisportion = GetPortion(psb, hwnd, &rect, pt.x, pt.y, scrollFlags);
+
+ //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_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(psb, &rect, scrollFlags);
+
+ OffsetRect(&rect, -winrect.left, -winrect.top);
+
+ if (thisportion != uCurrentScrollPortion)
+ {
+ uScrollTimerPortion = HTSCROLL_NONE;
+ if (lastportion != thisportion)
+ {
+ InvalidateNC(InvalidateFlag_Normal, uCurrentScrollbar);
+ }
+ }
+ //otherwise, draw the button in its depressed / clicked state
+ else
+ {
+ uScrollTimerPortion = uCurrentScrollPortion;
+ if (lastportion != thisportion)
+ {
+ InvalidateNC(InvalidateFlag_Normal, uCurrentScrollbar);
+ }
+ }
+ break;
+ }
+
+ lastportion = thisportion;
+ //lastbutton = buttonIdx;
+
+ //must return zero here, because we might get cursor anomilies
+ //CallWindowProc(sw->oldproc, hwnd, WM_MOUSEMOVE, wParam, lParam);
+
+ return;
+ }
+}
+
+//
+// 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
+//
+INT SkinnedScrollWnd::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS *pncsp)
+{
+ RECT *prc;
+ INT hcy, vcx, result;
+ BOOL bSizingDown;
+ prc = &pncsp->rgrc[0];
+ UINT updateBars = -1;
+
+ hcy = GetScrollMetric(psbHorz, SM_CYHORZSB, scrollFlags);
+ vcx = GetScrollMetric(psbVert, SM_CXVERTSB, scrollFlags);
+
+
+ if (SWS_UPDATEFRAME & scrollFlags)
+ {
+ // need to reset style
+ DWORD style;
+
+ scrollFlags &= ~SWS_UPDATEFRAME;
+ style = (DWORD)GetWindowLongPtrW(hwnd, GWL_STYLE);
+ if ((WS_HSCROLL | WS_VSCROLL) & style) SetWindowLongPtrW(hwnd, GWL_STYLE, style & ~(WS_HSCROLL | WS_VSCROLL));
+ CallDefWndProc(WM_NCCALCSIZE, (WPARAM)bCalcValidRects, (LPARAM)pncsp);
+ if ((WS_HSCROLL | WS_VSCROLL) & style) SetWindowLongPtrW(hwnd, GWL_STYLE, style);
+ }
+
+ result = __super::OnNcCalcSize(bCalcValidRects, pncsp);
+ bSizingDown = (bCalcValidRects &&
+ ((pncsp->rgrc[0].right - pncsp->rgrc[0].left) < (pncsp->rgrc[1].right - pncsp->rgrc[1].left) ||
+ (pncsp->rgrc[0].bottom - pncsp->rgrc[0].top) < (pncsp->rgrc[1].bottom - pncsp->rgrc[1].top)));
+
+
+ //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 ((psbHorz->fScrollFlags & CSBS_VISIBLE) && (prc->bottom - prc->top)
+#ifdef COOLSB_FILLWINDOW
+ >=
+#else
+ >
+#endif
+ hcy)
+ {
+ prc->bottom -= hcy;
+ if (TRUE != psbHorz->fScrollVisible)
+ {
+ psbHorz->fScrollVisible = TRUE;
+ updateBars = SB_HORZ;
+ }
+ }
+ else
+ {
+ if (FALSE != psbHorz->fScrollVisible)
+ {
+ psbHorz->fScrollVisible = FALSE;
+ updateBars = SB_HORZ;
+ }
+ }
+
+ //if there is room, allocate some space for the vertical scrollbar
+ if ((psbVert->fScrollFlags & CSBS_VISIBLE) && (prc->right - prc->left) >= vcx)
+ {
+ if (SWS_LEFT & scrollFlags) prc->left += vcx;
+ else prc->right -= vcx;
+ if (TRUE != psbVert->fScrollVisible)
+ {
+ psbVert->fScrollVisible = TRUE;
+ updateBars = (SB_HORZ == updateBars) ? SB_BOTH : SB_VERT;
+ }
+
+ }
+ else
+ {
+ if (FALSE != psbVert->fScrollVisible)
+ {
+ psbVert->fScrollVisible = FALSE;
+ updateBars = (SB_HORZ == updateBars) ? SB_BOTH : SB_VERT;
+ }
+ }
+
+ if (-1 != updateBars)
+ {
+ if (SWS_COMBOLBOX & scrollFlags)
+ {
+ InvalidateNC(InvalidateFlag_RedrawNow, updateBars);
+ }
+ else if (bSizingDown)
+ {
+ PostMessageW(hwnd, WM_ML_IPC, TRUE, IPC_ML_SKINNEDSCROLLWND_UPDATEBARS);
+ }
+
+ }
+
+ return result;
+}
+
+void SkinnedScrollWnd::OnNcMouseLeave()
+{
+ if (HTSCROLL_NONE != scrollPortionHover)
+ {
+ scrollPortionHover=HTSCROLL_NONE;
+ InvalidateNC(InvalidateFlag_Normal, SB_BOTH);
+ }
+}
+//
+// used for hot-tracking over the scroll buttons
+//
+void SkinnedScrollWnd::OnNcMouseMove(UINT nHitTest, POINTS pts)
+{
+ if (!bDoHover)
+ {
+ __super::WindowProc(WM_NCMOUSEMOVE, nHitTest, *(LPARAM*)&pts);
+ return;
+ }
+ SCROLLBAR *psb=0;
+ UINT scrollbar=0;
+ RECT rect;
+
+ if (psbHorz) psbHorz->fScrollFlags &= ~CSBS_HOVERING;
+ if (psbVert) psbVert->fScrollFlags &= ~CSBS_HOVERING;
+ if (HTHSCROLL == nHitTest)
+ {
+ psb = psbHorz;
+ scrollbar = SB_HORZ;
+ //get the total area of the normal Horz scrollbar area
+ GetHScrollRect(this, &rect);
+ }
+ //
+ // VERTICAL SCROLLBAR PROCESSING
+ //
+ else if (HTVSCROLL== nHitTest)
+ {
+ psb = psbVert;
+ scrollbar = SB_VERT;
+ //get the total area of the normal Horz scrollbar area
+ GetVScrollRect(this, &rect);
+ }
+ //
+ // NORMAL PROCESSING
+ //
+ else
+ {
+
+ scrollPortionHover=HTSCROLL_NONE;
+ __super::WindowProc(WM_NCMOUSEMOVE, nHitTest, *(LPARAM*)&pts);
+
+ return;
+ }
+
+ if (NULL != psb)
+ {
+ psb->fScrollFlags |= CSBS_HOVERING;
+ UINT thisportion = GetPortion(psb, hwnd, &rect, pts.x, pts.y, scrollFlags);
+ if (thisportion != scrollPortionHover)
+ {
+ TRACKMOUSEEVENT tracker;
+ tracker.cbSize = sizeof(tracker);
+ tracker.hwndTrack = hwnd;
+ tracker.dwHoverTime=0;
+ tracker.dwFlags = TME_LEAVE |TME_NONCLIENT; // benski> TME_NONCLIENT doesn't work on NT4.0, and we can work around it anyway
+ if (TrackMouseEvent(&tracker))
+ {
+ scrollPortionHover=thisportion;
+ InvalidateNC(InvalidateFlag_Normal, scrollbar);
+ }
+ }
+ }
+
+ __super::WindowProc(WM_NCMOUSEMOVE, nHitTest, *(LPARAM*)&pts);
+}
+
+//
+// Timer routine to generate scrollbar messages
+//
+void SkinnedScrollWnd::OnTimer(UINT_PTR idEvent, TIMERPROC fnTimer)
+{
+ //let all timer messages go past if we don't have a timer installed ourselves
+ if (uScrollTimerId != 0)
+ {
+ //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 (idEvent == COOLSB_TIMERID1)
+ {
+ KillTimer(hwnd, uScrollTimerId);
+ uScrollTimerId = SetTimer(hwnd, COOLSB_TIMERID2, COOLSB_TIMERINTERVAL2, 0);
+ return;
+ }
+ //send the scrollbar message repeatedly
+ else if (idEvent == 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);
+ MapWindowPoints(HWND_DESKTOP, hwnd, &pt, 1);
+ pt.x = POINTTOPOINTS(pt);
+ OnMouseMove(MK_LBUTTON, MAKEPOINTS(pt.x));
+ if (uScrollTimerPortion != HTSCROLL_NONE) SendScrollMessage(hwnd, uScrollTimerMsg, uScrollTimerPortion, 0);
+ UpdateScrollBars(TRUE);
+ return;
+ }
+ }
+ __super::WindowProc(WM_TIMER, (WPARAM)idEvent, (LPARAM)fnTimer);
+}
+
+//
+// We must intercept any calls to SetWindowLong, to check if
+// left-scrollbars are taking effect or not
+//
+
+static UINT curTool = -1;
+
+static LRESULT SendToolTipMessage0(HWND hwndTT, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ return SendMessageW(hwndTT, message, wParam, lParam);
+}
+
+#ifdef COOLSB_TOOLTIPS
+#define SendToolTipMessage SendToolTipMessage0
+#else
+#define SendToolTipMessage 1 ? (void)0 : SendToolTipMessage0
+#endif
+
+void SkinnedScrollWnd::OnStyleChanged(INT styleType, STYLESTRUCT *pss)
+{
+ if (styleType == GWL_EXSTYLE) scrollFlags = (scrollFlags & ~SWS_LEFT) | ((WS_EX_LEFTSCROLLBAR & pss->styleNew) ? SWS_LEFT : 0);
+ __super::OnStyleChanged(styleType, pss);
+}
+
+LRESULT SkinnedScrollWnd::OnEraseBackground(HDC hdc)
+{
+ if (0 == (CSBS_TRACKING & psbVert->fScrollFlags) && 0 == (CSBS_TRACKING & psbHorz->fScrollFlags) && uCurrentScrollPortion == HTSCROLL_NONE)
+ {
+ LRESULT result;
+ result = __super::WindowProc(WM_ERASEBKGND, (WPARAM)hdc, 0L);
+ UpdateScrollBars(TRUE);
+ return result;
+ }
+ return __super::WindowProc(WM_ERASEBKGND, (WPARAM)hdc, 0L);
+}
+
+
+void SkinnedScrollWnd::OnPrint(HDC hdc, UINT options)
+{
+ if ((PRF_NONCLIENT & options) &&
+ (0 == (PRF_CHECKVISIBLE & options) || IsWindowVisible(hwnd)))
+ {
+ PaintNonClient(hdc);
+ if (PRF_CLIENT & options)
+ CallPrevWndProc(WM_PRINT, (WPARAM)hdc, (LPARAM)(~(PRF_NONCLIENT | PRF_CHECKVISIBLE) & options));
+ }
+ else __super::OnPrint(hdc, options);
+}
+
+LRESULT SkinnedScrollWnd::OnListViewScroll(INT dx, INT dy)
+{
+ if (0 != dy &&
+ 0 != (SWS_LISTVIEW & scrollFlags) &&
+ 0 != (SWS_HIDEHSCROLL & scrollFlags) &&
+ (psbHorz->scrollInfo.nPage <= (UINT)psbHorz->scrollInfo.nMax))
+ {
+ DWORD windowStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
+ if (LVS_REPORT == (LVS_TYPEMASK & windowStyle))
+ {
+ SCROLLINFO scrollInfo;
+ scrollInfo.cbSize = sizeof(SCROLLINFO);
+ scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
+ if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo))
+ {
+ if (0 == dy ||
+ (scrollInfo.nPos == scrollInfo.nMin && dy < 0) ||
+ (scrollInfo.nPos >= (scrollInfo.nMax - (INT)scrollInfo.nPage) && dy > 0))
+ return TRUE;
+
+ RECT rc;
+ rc.left = LVIR_BOUNDS;
+ if (SendMessageW(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rc))
+ {
+ dy = dy / (rc.bottom - rc.top);
+ if (dy < 0)
+ {
+ if ((scrollInfo.nPos - dy) < scrollInfo.nMin)
+ dy = scrollInfo.nMin - scrollInfo.nPos;
+ }
+ else if (dy > 0)
+ {
+ if ((scrollInfo.nPos + dy) >= (scrollInfo.nMax - (INT)scrollInfo.nPage))
+ dy = scrollInfo.nMax - (INT)scrollInfo.nPage - scrollInfo.nPos;
+ }
+
+ dy = dy * (rc.bottom - rc.top);
+
+ if (0 == dy)
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ LRESULT result = __super::WindowProc(LVM_SCROLL, (WPARAM)dx, (LPARAM)dy);
+ if (result) UpdateScrollBars(TRUE);
+ return result;
+}
+
+void SkinnedScrollWnd::OnVertScroll(UINT code, UINT pos, HWND hwndSB)
+{
+ if (0 != (SWS_LISTVIEW & scrollFlags) &&
+ 0 != (SWS_HIDEHSCROLL & scrollFlags) &&
+ (psbHorz->scrollInfo.nPage <= (UINT)psbHorz->scrollInfo.nMax))
+ {
+ DWORD windowStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
+ if (LVS_REPORT == (LVS_TYPEMASK & windowStyle))
+ {
+ SCROLLINFO scrollInfo;
+ scrollInfo.cbSize = sizeof(SCROLLINFO);
+
+ switch(code)
+ {
+ case SB_LINEDOWN:
+ scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
+ if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo)
+ && scrollInfo.nPos >= (scrollInfo.nMax - (INT)scrollInfo.nPage))
+ return;
+ break;
+ }
+ }
+ }
+ __super::WindowProc(WM_VSCROLL, MAKEWPARAM(code, pos), (LPARAM)hwndSB);
+}
+
+
+void SkinnedScrollWnd::OnMouseWheel(INT delta, UINT vtKey, POINTS pts)
+{
+ if (0 == delta)
+ return;
+
+ if (0 != (SWS_LISTVIEW & scrollFlags))
+ {
+ DWORD windowStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
+ if (LVS_REPORT == (LVS_TYPEMASK & windowStyle))
+ {
+ if (0 != (WS_VSCROLL & windowStyle))
+ {
+ unsigned int wheelScroll;
+ int scrollLines, distance;
+
+ if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &wheelScroll, 0))
+ wheelScroll = 3;
+
+ if (0 == wheelScroll)
+ return;
+
+ if (WHEEL_PAGESCROLL == wheelScroll)
+ {
+ SendMessageW(hwnd, WM_VSCROLL, MAKEWPARAM(((delta > 0) ? SB_PAGEUP : SB_PAGEDOWN), 0), 0L);
+ SendMessageW(hwnd, WM_VSCROLL, MAKEWPARAM(SB_ENDSCROLL, 0), 0L);
+ return;
+ }
+
+ distance = delta + wheelCarryover;
+ scrollLines = distance * (INT)wheelScroll / WHEEL_DELTA;
+
+ wheelCarryover = distance - scrollLines * WHEEL_DELTA / (INT)wheelScroll;
+
+ if (ListView_ScrollReportModeVert(hwnd, -scrollLines, (0 != (SWS_HIDEHSCROLL & scrollFlags))))
+ {
+ InvalidateNC(InvalidateFlag_RedrawNow, SB_VERT);
+ return;
+ }
+ }
+ else if (0 != (SWS_HIDEHSCROLL & scrollFlags))
+ {
+ return;
+ }
+ }
+
+ }
+ __super::WindowProc(WM_MOUSEWHEEL, MAKEWPARAM(vtKey, delta), *(LPARAM*)&pts);
+}
+
+void SkinnedScrollWnd::UpdateFrame()
+{
+ if (SWS_UPDATEFRAME & scrollFlags)
+ {
+ SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_NOSENDCHANGING | SWP_NOREDRAW);
+ }
+}
+
+void SkinnedScrollWnd::OnSkinChanged(BOOL bNotifyChildren, BOOL bRedraw)
+{
+ UINT newFlag = scrollFlags & ~SWS_USEFREEFORM;
+ if (UseFreeformScrollbars())
+ newFlag |= SWS_USEFREEFORM;
+
+ if (newFlag != scrollFlags)
+ {
+ RECT rcOld;
+ GetClientRect(hwnd, &rcOld);
+
+ scrollFlags = newFlag;
+ SetWindowPos(hwnd, NULL, 0, 0, 0, 0,
+ SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOREDRAW);
+
+ }
+ __super::OnSkinChanged(bNotifyChildren, bRedraw);
+
+ if (FALSE != bRedraw)
+ RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE |RDW_ERASE | RDW_FRAME);
+}
+
+LRESULT SkinnedScrollWnd::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ /*case SBM_GETSCROLLINFO:
+ {
+ SCROLLINFO *scrollInfo = (SCROLLINFO *)lParam;
+ int x=0;
+ x=0;
+ }
+ break;*/
+
+ case WM_NCMOUSEMOVE: OnNcMouseMove((UINT)wParam, MAKEPOINTS(lParam)); return 0;
+ case WM_NCRBUTTONDOWN:
+ case WM_NCRBUTTONUP:
+ case WM_NCMBUTTONDOWN:
+ case WM_NCMBUTTONUP: if (wParam == HTHSCROLL || wParam == HTVSCROLL) return 0;
+ break;
+ case WM_NCLBUTTONDBLCLK: if (wParam != HTHSCROLL && wParam != HTVSCROLL) break; // else fall to the nclbuttondown
+ case WM_NCLBUTTONDOWN: OnNcLButtonDown((UINT)wParam, MAKEPOINTS(lParam)); return 0;
+ case WM_NCMOUSELEAVE:
+ case WM_MOUSELEAVE: OnNcMouseLeave(); break;
+ case WM_LBUTTONUP: OnLButtonUp((UINT)wParam, MAKEPOINTS(lParam)); return 0;
+ case WM_MOUSEMOVE: OnMouseMove((UINT)wParam, MAKEPOINTS(lParam)); return 0;
+ case WM_TIMER: OnTimer((UINT_PTR)wParam, (TIMERPROC)lParam); return 0;
+ case WM_ERASEBKGND: return OnEraseBackground((HDC)wParam);
+ case WM_DISPLAYCHANGE:
+ SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_NOSENDCHANGING);
+ break;
+ case WM_CAPTURECHANGED:
+ if (!ignoreCaptureChange)
+ {
+ LONG pts = GetMessagePos();
+ POINT pt;
+ POINTSTOPOINT(pt, pts);
+ MapWindowPoints(HWND_DESKTOP, hwnd, &pt, 1);
+ pts = POINTTOPOINTS(pt);
+ Emulate_LeftButtonUp((UINT)wParam, MAKEPOINTS(pts), FALSE);
+ }
+ break;
+ // sometimes update frame required when this messges arrive
+ case WM_ACTIVATE:
+ case WM_SETFOCUS:
+ case WM_HSCROLL:
+ {
+ LRESULT result = __super::WindowProc(uMsg, wParam, lParam);
+ UpdateFrame();
+ return result;
+ }
+ break;
+ case WM_MOUSEWHEEL:
+ OnMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam), GET_KEYSTATE_WPARAM(wParam), MAKEPOINTS(lParam));
+ UpdateFrame();
+ return 0;
+ case WM_VSCROLL:
+ OnVertScroll(LOWORD(wParam), HIWORD(wParam), (HWND)lParam);
+ UpdateFrame();
+ return 0;
+ case LVM_SCROLL:
+ if (SWS_LISTVIEW & scrollFlags)
+ return OnListViewScroll((INT)wParam, (INT)lParam);
+ break;
+ case WM_KEYDOWN:
+ if (0 != ((SWS_LISTVIEW | SWS_TREEVIEW ) & scrollFlags))
+ {
+ LRESULT result = __super::WindowProc(uMsg, wParam, lParam);
+ switch(wParam)
+ {
+ case VK_PRIOR:
+ case VK_NEXT:
+ case VK_UP:
+ case VK_DOWN:
+ case VK_HOME:
+ case VK_END:
+ UpdateScrollBars(TRUE);
+ break;
+ }
+ return result;
+ }
+ break;
+ case WM_USER + 0x3443:
+ UpdateScrollBars(TRUE);
+ break;
+ }
+ return __super::WindowProc(uMsg, wParam, lParam);
+}
+
+//
+// return the default minimum size of a scrollbar thumb
+//
+static 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
+ return (dwVersion >= 0x80000000 && LOBYTE(LOWORD(dwVersion)) >= 5) ? MINTHUMBSIZE_2000 : MINTHUMBSIZE_NT4;
+}
+
+BOOL SkinnedScrollWnd::ShowScrollBar(int wBar, BOOL fShow)
+{
+ DWORD styleOld, styleNew;
+
+ styleOld = GetWindowLongPtrW(hwnd, GWL_STYLE);
+ styleNew = styleOld;
+
+ if (wBar == SB_HORZ || wBar == SB_BOTH)
+ {
+ psbHorz->fScrollFlags = (psbHorz->fScrollFlags & ~CSBS_VISIBLE) | ((fShow) ? CSBS_VISIBLE : 0);
+ styleNew = (styleNew & ~WS_HSCROLL) | ((fShow) ? WS_HSCROLL :0);
+ }
+
+ if (wBar == SB_VERT || wBar == SB_BOTH)
+ {
+ psbVert->fScrollFlags = (psbVert->fScrollFlags & ~CSBS_VISIBLE) | ((fShow) ? CSBS_VISIBLE : 0);
+ styleNew = (styleNew & ~WS_VSCROLL) | ((fShow) ? WS_VSCROLL :0);
+ }
+
+ if (styleNew != styleOld)
+ {
+ SetWindowLongPtrW(hwnd, GWL_STYLE, styleNew);
+ SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_NOREDRAW);
+ }
+
+ return TRUE;
+}
+
+SkinnedScrollWnd::SkinnedScrollWnd(BOOL bIsDialog)
+ : SkinnedWnd(bIsDialog), psbHorz(0), psbVert(0),
+ scrollFlags(0), scrollPortionHover(0), wheelCarryover(0)
+{
+ if (-1 == bUseUpdateRgn)
+ {
+ OSVERSIONINFO osver = {0};
+ osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ if (::GetVersionEx(&osver))
+ {
+ bUseUpdateRgn =
+ ((VER_PLATFORM_WIN32_NT != osver.dwPlatformId ||
+ (osver.dwMajorVersion < 6 && osver.dwMinorVersion != 2)));
+ bDoHover = !(VER_PLATFORM_WIN32_NT == osver.dwPlatformId && osver.dwMajorVersion == 4); // can't use TrackMouseEvent with non-client areas on Windows NT 4.0
+ }
+ }
+}
+
+BOOL SkinnedScrollWnd::Attach(HWND hwndToSkin)
+{
+ DWORD style;
+
+ if (!SkinnedWnd::Attach(hwndToSkin))
+ return FALSE;
+
+ SetType(SKINNEDWND_TYPE_SCROLLWND);
+
+ psbHorz = (SCROLLBAR*)calloc(1, sizeof(SCROLLBAR));
+ psbVert = (SCROLLBAR*)calloc(1, sizeof(SCROLLBAR));
+ if (!psbHorz || !psbVert) return FALSE;
+
+ scrollFlags = 0;
+ wheelCarryover = 0;
+
+ psbHorz->scrollInfo.cbSize = sizeof(SCROLLINFO);
+ psbHorz->scrollInfo.fMask = SIF_ALL;
+ if (!GetScrollInfo(hwnd, SB_HORZ, &psbHorz->scrollInfo))
+ ZeroMemory(&psbHorz->scrollInfo, sizeof(SCROLLINFO));
+
+ psbVert->scrollInfo.cbSize = sizeof(SCROLLINFO);
+ psbVert->scrollInfo.fMask = SIF_ALL;
+ if (!GetScrollInfo(hwnd, SB_VERT, &psbVert->scrollInfo))
+ ZeroMemory(&psbVert->scrollInfo, sizeof(SCROLLINFO));
+
+ scrollPortionHover = HTSCROLL_NONE;
+
+ //check to see if the window has left-aligned scrollbars
+ if (GetWindowLongPtrW(hwnd, GWL_EXSTYLE) & WS_EX_LEFTSCROLLBAR) scrollFlags |= SWS_LEFT;
+
+ style = GetWindowLongPtrW(hwnd, GWL_STYLE);
+
+ if (WS_HSCROLL & style) psbHorz->fScrollFlags = CSBS_VISIBLE;
+ if (WS_VSCROLL & style) psbVert->fScrollFlags = CSBS_VISIBLE;
+
+ psbHorz->nBarType = SB_HORZ;
+ psbVert->nBarType = SB_VERT;
+
+ //set the default arrow sizes for the scrollbars
+ psbHorz->nMinThumbSize = CoolSB_GetDefaultMinThumbSize();
+ psbVert->nMinThumbSize = psbHorz->nMinThumbSize;
+
+ scrollFlags |= SWS_UPDATEFRAME;
+ SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_NOSENDCHANGING | SWP_NOREDRAW);
+ InvalidateNC(InvalidateFlag_Frame | InvalidateFlag_RedrawNow, SB_BOTH);
+
+ return TRUE;
+}
+
+SkinnedScrollWnd::~SkinnedScrollWnd(void)
+{
+ InvalidateNC(InvalidateFlag_Frame | InvalidateFlag_RedrawNow, SB_BOTH);
+ if (psbHorz) free(psbHorz);
+ if (psbVert) free(psbVert);
+ if (hbrChecked)
+ {
+ DeleteObject(hbrChecked);
+ hbrChecked = NULL;
+ }
+}
+
+void SkinnedScrollWnd::DisableNoScroll(BOOL bDisable)
+{
+ if (bDisable) scrollFlags |= SWS_DISABLENOSCROLL;
+ else scrollFlags &= ~SWS_DISABLENOSCROLL;
+}
+BOOL SkinnedScrollWnd::IsNoScrollDisabled()
+{
+ return (0 != (SWS_DISABLENOSCROLL & scrollFlags));
+}
+
+void SkinnedScrollWnd::InvalidateNC(InvalidateFlags invalidate, UINT bars)
+{
+ HRGN rgnH = NULL, rgnV = NULL;
+ RECT rc;
+ int scrollLength;
+ unsigned int flags;
+ long frameEdge, clientEdge;
+
+ if (0 != (InvalidateFlag_Frame & invalidate))
+ {
+ flags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE |
+ SWP_FRAMECHANGED | SWP_NOSENDCHANGING | SWP_NOREDRAW;
+
+ SetWindowPos(hwnd, NULL, 0, 0, 0, 0, flags);
+ }
+
+ if (FALSE == GetClientRect(hwnd, &rc))
+ return;
+
+ if (SB_HORZ == bars || SB_BOTH == bars)
+ {
+ scrollLength = GetScrollMetric(psbHorz, SM_CYVERTSB, scrollFlags);
+
+ clientEdge = rc.bottom;
+ if (0 != (InvalidateFlag_HorzBarRemoved & invalidate))
+ clientEdge -= scrollLength;
+
+ frameEdge = clientEdge + scrollLength;
+
+ rgnH = CreateRectRgn(rc.left, clientEdge, rc.right, frameEdge);
+ }
+ else
+ rgnH = NULL;
+
+ if (SB_VERT == bars || SB_BOTH == bars)
+ {
+ scrollLength = GetScrollMetric(psbVert, SM_CXVERTSB, scrollFlags);
+
+ if (0 != (SWS_LEFT & scrollFlags))
+ {
+ clientEdge = rc.left;
+ if (0 == (InvalidateFlag_VertBarRemoved & invalidate))
+ clientEdge -= scrollLength;
+ }
+ else
+ {
+ clientEdge = rc.right;
+ if (0 != (InvalidateFlag_VertBarRemoved & invalidate))
+ clientEdge -= scrollLength;
+
+ frameEdge = clientEdge + scrollLength;
+ }
+
+ rgnV = CreateRectRgn(clientEdge, rc.top, frameEdge, rc.bottom);
+
+ if (NULL != rgnV && SB_BOTH == bars)
+ CombineRgn(rgnH, rgnH, rgnV, RGN_OR);
+ }
+ else
+ rgnV = NULL;
+
+ flags = RDW_INVALIDATE | /*RDW_INTERNALPAINT | RDW_ERASE |*/ RDW_FRAME | RDW_NOCHILDREN;
+ if (0 != (InvalidateFlag_RedrawNow & invalidate))
+ flags |= (RDW_UPDATENOW | RDW_ERASENOW);
+
+ HRGN rgn = ((NULL != rgnH) ? rgnH : rgnV);
+ if (rgn)
+ RedrawWindow(hwnd, NULL, rgn, flags);
+
+ if (rgnH)
+ DeleteRgn(rgnH);
+
+ if (rgnV)
+ DeleteRgn(rgnV);
+}
+
+void SkinnedScrollWnd::UpdateScrollBars(BOOL fInvalidate)
+{
+ UINT bars;
+ InvalidateFlags invalidateFlags;
+
+ SCROLLINFO tsi;
+ tsi.cbSize = sizeof(SCROLLINFO);
+ tsi.fMask = SIF_ALL;
+
+ bars = -1;
+ invalidateFlags = InvalidateFlag_Normal /*| InvalidateFlag_RedrawNow*/;
+
+ if (0 == (SWS_HIDEHSCROLL & scrollFlags))
+ {
+ if (GetScrollInfo(hwnd, SB_HORZ, &tsi) &&
+ memcmp(&tsi, &psbHorz->scrollInfo, sizeof(SCROLLINFO)))
+ {
+ memcpy(&psbHorz->scrollInfo, &tsi, sizeof(SCROLLINFO));
+ UpdateScrollBar(psbHorz, &invalidateFlags);
+
+ psbHorz->scrollInfo.cbSize = sizeof(SCROLLINFO);
+ psbHorz->scrollInfo.fMask = SIF_ALL;
+ if (!GetScrollInfo(hwnd, SB_HORZ, &psbHorz->scrollInfo))
+ ZeroMemory(&psbHorz->scrollInfo, sizeof(SCROLLINFO));
+
+ bars = SB_HORZ;
+ }
+ }
+ else
+ {
+ psbHorz->scrollInfo.cbSize = sizeof(SCROLLINFO);
+ psbHorz->scrollInfo.fMask = SIF_ALL;
+ if (!GetScrollInfo(hwnd, SB_HORZ, &psbHorz->scrollInfo))
+ ZeroMemory(&psbHorz->scrollInfo, sizeof(SCROLLINFO));
+ }
+
+ if (0 == (SWS_HIDEVSCROLL & scrollFlags))
+ {
+ if (GetScrollInfo(hwnd, SB_VERT, &tsi))
+ {
+ if (0 != (SWS_LISTVIEW & scrollFlags) &&
+ LVS_REPORT == (LVS_TYPEMASK & GetWindowLongPtrW(hwnd, GWL_STYLE)))
+ {
+ if (0 != (SWS_HIDEHSCROLL & scrollFlags))
+ {
+ tsi.nMax = (int)SendMessageW(hwnd, LVM_GETITEMCOUNT, 0, 0L);
+ tsi.nPage = (unsigned int)SendMessageW(hwnd, LVM_GETCOUNTPERPAGE, 0, 0L);
+ if(tsi.nMax > 0)
+ tsi.nMax--;
+
+ // if (psbHorz->scrollInfo.nPage <= (UINT)psbHorz->scrollInfo.nMax)
+
+ }
+ }
+
+ if (memcmp(&tsi, &psbVert->scrollInfo, sizeof(SCROLLINFO)))
+ {
+ memcpy(&psbVert->scrollInfo, &tsi, sizeof(SCROLLINFO));
+
+ UpdateScrollBar(psbVert, &invalidateFlags);
+ bars = (SB_HORZ == bars) ? SB_BOTH : SB_VERT;
+ }
+ }
+ }
+ else
+ {
+ psbVert->scrollInfo.cbSize = sizeof(SCROLLINFO);
+ psbVert->scrollInfo.fMask = SIF_ALL;
+ if (!GetScrollInfo(hwnd, SB_VERT, &psbVert->scrollInfo))
+ ZeroMemory(&psbVert->scrollInfo, sizeof(SCROLLINFO));
+ }
+
+ if ((fInvalidate || 0 != (InvalidateFlag_Frame & invalidateFlags)) &&
+ -1 != bars)
+ {
+ InvalidateNC(invalidateFlags, bars);
+
+ if (0 != (InvalidateFlag_Frame & invalidateFlags) &&
+ 0 != (SWS_LISTVIEW & scrollFlags) &&
+ LVS_REPORT == (LVS_TYPEMASK & GetWindowLongPtrW(hwnd, GWL_STYLE)))
+ {
+ if (0 == (LVS_NOCOLUMNHEADER & GetWindowLongPtrW(hwnd, GWL_STYLE)))
+ {
+ HWND hHeader = (HWND)SendMessageW(hwnd, LVM_GETHEADER, 0, 0L);
+ if (NULL != hHeader)
+ {
+ RECT clientRect;
+ WINDOWPOS wp;
+
+ GetClientRect(hwnd, &clientRect);
+
+ SCROLLINFO si;
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_POS;
+ if (0 != GetScrollInfo(hwnd, SB_HORZ, &si))
+ clientRect.left -= si.nPos;
+
+ HDLAYOUT layout;
+ layout.prc = &clientRect;
+ layout.pwpos = &wp;
+ if (FALSE != SendMessageW(hHeader, HDM_LAYOUT, 0, (LPARAM)&layout))
+ {
+ if (FALSE == fInvalidate)
+ wp.flags |= SWP_NOREDRAW;
+ SetWindowPos(hHeader, wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags | SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+ }
+ }
+ }
+ }
+}
+
+void SkinnedScrollWnd::UpdateScrollBar(SCROLLBAR *psb, InvalidateFlags *invalidateFlags)
+{
+ SCROLLINFO *psi;
+ psi = &psb->scrollInfo;
+
+ if ((psi->nPage > (UINT)psi->nMax || (psi->nPage == (UINT)psi->nMax && psi->nMax == 0) || psi->nMax <= psi->nMin))
+ {
+ if (psb->fScrollVisible)
+ {
+ if (SWS_DISABLENOSCROLL & scrollFlags)
+ {
+ psb->fScrollFlags |= (ESB_DISABLE_LEFT | ESB_DISABLE_RIGHT);
+ }
+ else
+ {
+ ShowScrollBar(psb->nBarType, FALSE);
+ *invalidateFlags |= InvalidateFlag_Frame;
+ if (SB_VERT == psb->nBarType)
+ *invalidateFlags |= InvalidateFlag_VertBarRemoved;
+ else
+ *invalidateFlags |= InvalidateFlag_HorzBarRemoved;
+ }
+ }
+ }
+ else
+ {
+ if ((!psb->fScrollVisible || ((ESB_DISABLE_LEFT | ESB_DISABLE_RIGHT) & psb->fScrollFlags)) && psi->nPage > 0)
+ {
+ if ((SWS_DISABLENOSCROLL & scrollFlags) && ((ESB_DISABLE_LEFT | ESB_DISABLE_RIGHT) & psb->fScrollFlags))
+ {
+ psb->fScrollFlags &= ~(ESB_DISABLE_LEFT | ESB_DISABLE_RIGHT);
+ }
+
+ if (!psb->fScrollVisible)
+ {
+ if (SWS_LISTVIEW & scrollFlags)
+ {
+ DWORD ws = GetWindowLongPtrW(hwnd, GWL_STYLE);
+ if (LVS_ICON == (LVS_TYPEMASK & ws) || LVS_SMALLICON == (LVS_TYPEMASK & ws))
+ {
+ switch(LVS_ALIGNMASK & ws)
+ {
+ case LVS_ALIGNLEFT:
+ if (SB_HORZ != psb->nBarType) psb->nBarType = ((SB_BOTH == psb->nBarType) ? SB_HORZ : -1);
+ break;
+ case LVS_ALIGNTOP:
+ if (SB_VERT != psb->nBarType) psb->nBarType = ((SB_BOTH == psb->nBarType) ? SB_VERT : -1);
+ break;
+ }
+ }
+ }
+ if (-1 != psb->nBarType)
+ {
+ ShowScrollBar(psb->nBarType, TRUE);
+ *invalidateFlags |= InvalidateFlag_Frame;
+ if (SB_VERT == psb->nBarType)
+ *invalidateFlags |= InvalidateFlag_VertBarAppeared;
+ else
+ *invalidateFlags |= InvalidateFlag_HorzBarAppeared;
+ }
+ }
+ }
+ else if (psb->fScrollVisible && 0 == psi->nPage)
+ {
+ if (SWS_DISABLENOSCROLL & scrollFlags)
+ {
+ psb->fScrollFlags |= (ESB_DISABLE_LEFT | ESB_DISABLE_RIGHT);
+ }
+ else
+ {
+ ShowScrollBar(psb->nBarType, FALSE);
+ *invalidateFlags |= InvalidateFlag_Frame;
+ if (SB_VERT == psb->nBarType)
+ *invalidateFlags |= InvalidateFlag_VertBarRemoved;
+ else
+ *invalidateFlags |= InvalidateFlag_HorzBarRemoved;
+ }
+ }
+ }
+}
+
+void SkinnedScrollWnd::ShowHorzScroll(BOOL fEnable)
+{
+ scrollFlags = (scrollFlags & ~SWS_HIDEHSCROLL) | ((fEnable) ? 0 : SWS_HIDEHSCROLL);
+ psbHorz->fScrollFlags = 0;
+ InvalidateNC(InvalidateFlag_Frame | InvalidateFlag_RedrawNow, SB_HORZ);
+}
+
+BOOL SkinnedScrollWnd::IsHorzBarHidden()
+{
+ return (0 != (SWS_HIDEHSCROLL & scrollFlags));
+}
+
+BOOL SkinnedScrollWnd::IsVertBarHidden()
+{
+ return (0 != (SWS_HIDEVSCROLL & scrollFlags));
+}
+
+void SkinnedScrollWnd::ShowVertScroll(BOOL fEnable)
+{
+ scrollFlags = (scrollFlags & ~SWS_HIDEVSCROLL) | ((fEnable) ? 0 : SWS_HIDEVSCROLL);
+ psbVert->fScrollFlags = 0;
+ InvalidateNC(InvalidateFlag_Frame | InvalidateFlag_RedrawNow, SB_VERT);
+}
+
+BOOL SkinnedScrollWnd::SetMode(UINT nMode)
+{
+ scrollFlags &= ~(SWS_LISTVIEW | SWS_TREEVIEW | SWS_COMBOLBOX);
+ switch (0xFF & nMode)
+ {
+ case SCROLLMODE_STANDARD_I: return TRUE;
+ case SCROLLMODE_LISTVIEW_I: scrollFlags |= SWS_LISTVIEW; return TRUE;
+ case SCROLLMODE_TREEVIEW_I: scrollFlags |= SWS_TREEVIEW; return TRUE;
+ case SCROLLMODE_COMBOLBOX_I: scrollFlags |= SWS_COMBOLBOX; return TRUE;
+ }
+
+ return FALSE;
+}
+
+UINT SkinnedScrollWnd::GetMode()
+{
+ if (0 != (SWS_LISTVIEW & scrollFlags))
+ return SCROLLMODE_STANDARD_I;
+
+ if (0 != (SWS_TREEVIEW & scrollFlags))
+ return SCROLLMODE_TREEVIEW_I;
+
+ if (0 != (SWS_COMBOLBOX & scrollFlags))
+ return SCROLLMODE_COMBOLBOX_I;
+
+ return SCROLLMODE_STANDARD_I;
+}
+
+INT SkinnedScrollWnd::AdjustHover(UINT nHitTest, POINTS pts)
+{
+ SCROLLBAR *psb = NULL;
+ RECT rect;
+
+ if (psbHorz) psbHorz->fScrollFlags &= ~CSBS_HOVERING;
+ if (psbVert) psbVert->fScrollFlags &= ~CSBS_HOVERING;
+ scrollPortionHover = HTSCROLL_NONE;
+
+ if (HTHSCROLL == nHitTest)
+ {
+ psb = psbHorz;
+ GetHScrollRect(this, &rect);
+ }
+ else if (HTVSCROLL== nHitTest)
+ {
+ psb = psbVert;
+ GetVScrollRect(this, &rect);
+ }
+
+ if (psb)
+ {
+ psb->fScrollFlags |= CSBS_HOVERING;
+ scrollPortionHover = GetPortion(psb, hwnd, &rect, pts.x, pts.y, scrollFlags);
+ }
+ return scrollPortionHover;
+}
+
+BOOL SkinnedScrollWnd::OnMediaLibraryIPC(INT msg, INT_PTR param, LRESULT *pResult)
+{
+ switch (msg)
+ {
+ case IPC_ML_SKINNEDSCROLLWND_UPDATEBARS:
+ UpdateScrollBars((BOOL)param);
+ *pResult = 1;
+ return TRUE;
+ case IPC_ML_SKINNEDSCROLLWND_SHOWHORZBAR:
+ ShowHorzScroll((BOOL)param);
+ *pResult = 1;
+ return TRUE;
+ case IPC_ML_SKINNEDSCROLLWND_SHOWVERTBAR:
+ ShowVertScroll((BOOL)param);
+ *pResult = 1;
+ return TRUE;
+ case IPC_ML_SKINNEDSCROLLWND_SETMODE:
+ *pResult = SetMode((UINT)param);
+ return TRUE;
+ case IPC_ML_SKINNEDSCROLLWND_DISABLENOSCROLL:
+ DisableNoScroll(0 != param);
+ *pResult = -1;
+ return TRUE;
+ case IPC_ML_SKINNEDSCROLLWND_ADJUSTHOVER:
+ ((SBADJUSTHOVER*)param)->nResult = AdjustHover(((SBADJUSTHOVER*)param)->hitTest, ((SBADJUSTHOVER*)param)->ptMouse);
+ *pResult = TRUE;
+ return TRUE;
+ case IPC_ML_SKINNEDSCROLLWND_GETHORZBARHIDDEN:
+ *pResult = IsHorzBarHidden();
+ return TRUE;
+ case IPC_ML_SKINNEDSCROLLWND_GETVERTBARHIDDEN:
+ *pResult = IsVertBarHidden();
+ return TRUE;
+ case IPC_ML_SKINNEDSCROLLWND_GETMODE:
+ *pResult = GetMode();
+ return TRUE;
+ case IPC_ML_SKINNEDSCROLLWND_GETNOSCROLLDISABLED:
+ *pResult = IsNoScrollDisabled();
+ return TRUE;
+ }
+ return __super::OnMediaLibraryIPC(msg, param, pResult);
+} \ No newline at end of file