mirror of
https://github.com/WinampDesktop/winamp.git
synced 2024-09-24 15:54:12 +00:00
3285 lines
89 KiB
C++
3285 lines
89 KiB
C++
|
// 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 = ▭
|
||
|
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 = ℘
|
||
|
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);
|
||
|
}
|