分类:
2008-06-03 09:35:18
//水平滚动条消息处理
static BOOL wndHandleHScrollBar (PMAINWIN pWin, int message, int x, int y)
{
static int downPos = SBPOS_UNKNOWN;
static int movePos = SBPOS_UNKNOWN;
static int sbCode;
static int oldBarStart;
static int oldThumbPos;
static int oldx;
int curPos;
RECT rcBar;
//获取水平滚动条矩形区域.
wndGetHScrollBarRect (pWin, &rcBar);
//计算滚动条除左右按钮后的矩形区域.
rcBar.left += GetMainWinMetrics (MWM_CXHSCROLL);
rcBar.right -= GetMainWinMetrics (MWM_CXHSCROLL);
//计算顶点对应的滚动条逻辑位置.
curPos = wndGetHScrollBarPos (pWin, x, y);
//若在滚动条区域外,则返回.
if (curPos == SBPOS_UNKNOWN && downPos == SBPOS_UNKNOWN)
{
return FALSE;
}
switch( message )
{
//若为鼠标左键按下。
case MSG_NCLBUTTONDOWN:
//记录开始位置
oldBarStart = pWin->hscroll.barStart;
oldThumbPos = pWin->hscroll.curPos;
oldx = x;
//保存当前位置。
downPos = curPos;
movePos = curPos;
//左按钮,向左翻页。
if (curPos == SBPOS_LEFTARROW)
{
sbDownButton (pWin, curPos);
if (pWin->hscroll.curPos == pWin->hscroll.minPos)
break;
sbCode = SB_LINELEFT;
}
//右按钮,向右翻页。
else if (curPos == SBPOS_RIGHTARROW)
{
sbDownButton (pWin, curPos);
if (pWin->hscroll.curPos == pWin->hscroll.maxPos)
break;
sbCode = SB_LINERIGHT;
}
//点击在滑块左边,向左滚动一单位。
else if (curPos == SBPOS_LEFTSPACE)
{
if (pWin->hscroll.curPos == pWin->hscroll.minPos)
break;
sbCode = SB_PAGELEFT;
}
//点击在滑块右边,向左滚动一单位。
else if (curPos == SBPOS_RIGHTSPACE)
{
if (pWin->hscroll.curPos == pWin->hscroll.maxPos)
break;
sbCode = SB_PAGERIGHT;
}
//拖动滑块.
else if (curPos == SBPOS_THUMB)
{
sbCode = SB_THUMBTRACK;
break;
}
//处理消息
SendNotifyMessage ((HWND)pWin, MSG_HSCROLL, sbCode, 0);
/*
设置默认自动回复消息,即按下按钮,按下滚动条除滑块以外的区域不动时,
会自动产生此消息.即当用户按住滚动条按钮不动时,将不停的发送翻页消息,
直到翻页到最边界的情况。
*/
SetAutoRepeatMessage ((HWND)pWin, MSG_HSCROLL, sbCode, 0);
break;
/*
若为左键松开
*/
case MSG_NCLBUTTONUP:
/*
若开始为拖动滑块。
*/
if (sbCode == SB_THUMBTRACK && downPos == SBPOS_THUMB)
{
/*
计算滑块被拖动的距离(象素为单位)
*/
int newBarStart = oldBarStart + x - oldx;
/*
根据滑块被拖动的距离计算滑块被拖动的逻辑滚动距离,然后当前滑块对应的逻辑位置。
*/
int newThumbPos = newBarStart
* (pWin->hscroll.maxPos - pWin->hscroll.minPos + 1)
/ (rcBar.right - rcBar.left) + pWin->hscroll.minPos;
/*
若计算出来的逻辑位置合法,则更新滚动条,发送拖动滑块完成消息(SB_THUMBPOSITION)。
*/
if (newThumbPos != oldThumbPos
&& newThumbPos >= pWin->hscroll.minPos
&& newThumbPos <= pWin->hscroll.maxPos)
SendNotifyMessage ((HWND)pWin,
MSG_HSCROLL, SB_THUMBPOSITION, newThumbPos);
/*
此时用户对滚动条的操作已经完成,清空上一次保存的位置信息,
确保下一次的滚动条操作开始时的参数正确。
*/
downPos = SBPOS_UNKNOWN;
movePos = SBPOS_UNKNOWN;
break;
}
/*
若为翻页,滚动信息,则处理消息.生成滚动条操作完成消息,取消自动恢复消息。
更新按钮显示状态。
*/
if (downPos != SBPOS_UNKNOWN)
{
sbUpButton (pWin, curPos);
SendNotifyMessage ((HWND)pWin, MSG_HSCROLL, SB_ENDSCROLL, 0);
SetAutoRepeatMessage (HWND_DESKTOP, 0, 0, 0);
}
downPos = SBPOS_UNKNOWN;
movePos = SBPOS_UNKNOWN;
break;
/*
若为鼠标移动信息
*/
case MSG_NCMOUSEMOVE:
/*
若用户曾按下滑块。则转换为拖动滑块消息.
*/
if (sbCode == SB_THUMBTRACK && downPos == SBPOS_THUMB)
{
/*
计算滑块拖动的距离(象素)
*/
int newBarStart = oldBarStart + x - oldx;
/*
根据前面计算的滑块拖动距离,计算滑块拖动的逻辑滚动距离,然后当前滑块对应的逻辑位置。
*/
int newThumbPos = newBarStart
* (pWin->hscroll.maxPos - pWin->hscroll.minPos + 1)
/ (rcBar.right - rcBar.left) + pWin->hscroll.minPos;
/*
若计算出来的逻辑位置合法,则更新滚动条,发送拖动滑块消息(SB_THUMBTRACK)。
*/
if (newThumbPos != oldThumbPos
&& newThumbPos >= pWin->hscroll.minPos
&& newThumbPos <= pWin->hscroll.maxPos)
{
SendNotifyMessage ((HWND)pWin,
MSG_HSCROLL, SB_THUMBTRACK, newThumbPos);
/*
更新上次拖动位置。
*/
oldThumbPos = newThumbPos;
}
movePos = curPos;
break;
}
//更新按钮显示状态。
if (movePos == downPos && curPos != downPos)
{
sbUpButton (pWin, downPos);
}
else if (movePos != downPos && curPos == downPos)
{
sbDownButton (pWin, downPos);
}
movePos = curPos;
break;
}
return TRUE;
}
//处理垂直滚动条事件,与水平滚动条处理方式一致.
static BOOL wndHandleVScrollBar (PMAINWIN pWin, int message, int x, int y)
{
static int downPos = SBPOS_UNKNOWN;
static int movePos = SBPOS_UNKNOWN;
static int sbCode;
static int oldBarStart;
static int oldThumbPos;
static int oldy;
int curPos;
RECT rcBar;
int newBarStart;
int newThumbPos;
wndGetVScrollBarRect (pWin, &rcBar);
rcBar.top += GetMainWinMetrics (MWM_CYVSCROLL);
rcBar.bottom -= GetMainWinMetrics (MWM_CYVSCROLL);
curPos = wndGetVScrollBarPos (pWin, x, y);
if (curPos == SBPOS_UNKNOWN && downPos == SBPOS_UNKNOWN)
return FALSE;
switch (message)
{
case MSG_NCLBUTTONDOWN:
oldBarStart = pWin->vscroll.barStart;
oldThumbPos = pWin->vscroll.curPos;
oldy = y;
downPos = curPos;
movePos = curPos;
if (curPos == SBPOS_UPARROW) {
sbDownButton (pWin, curPos);
if (pWin->vscroll.curPos == pWin->vscroll.minPos)
break;
sbCode = SB_LINEUP;
}
else if (curPos == SBPOS_DOWNARROW) {
sbDownButton (pWin, curPos);
if (pWin->vscroll.curPos == pWin->vscroll.maxPos)
break;
sbCode = SB_LINEDOWN;
}
else if (curPos == SBPOS_UPSPACE) {
if (pWin->vscroll.curPos == pWin->vscroll.minPos)
break;
sbCode = SB_PAGEUP;
}
else if (curPos == SBPOS_DOWNSPACE) {
if (pWin->vscroll.curPos == pWin->vscroll.maxPos)
break;
sbCode = SB_PAGEDOWN;
}
else if (curPos == SBPOS_THUMB) {
sbCode = SB_THUMBTRACK;
break;
}
SendNotifyMessage ((HWND)pWin, MSG_VSCROLL, sbCode, 0);
SetAutoRepeatMessage ((HWND)pWin, MSG_VSCROLL, sbCode, 0);
break;
case MSG_NCLBUTTONUP:
if (sbCode == SB_THUMBTRACK && downPos == SBPOS_THUMB) {
newBarStart = oldBarStart + y - oldy;
newThumbPos = newBarStart
* (pWin->vscroll.maxPos - pWin->vscroll.minPos + 1)
/ (rcBar.bottom - rcBar.top) + pWin->vscroll.minPos;
if (newThumbPos != oldThumbPos
&& newThumbPos >= pWin->vscroll.minPos
&& newThumbPos <= pWin->vscroll.maxPos)
SendNotifyMessage ((HWND)pWin,
MSG_VSCROLL, SB_THUMBPOSITION, newThumbPos);
downPos = SBPOS_UNKNOWN;
movePos = SBPOS_UNKNOWN;
break;
}
if (downPos != SBPOS_UNKNOWN) {
sbUpButton (pWin, curPos);
SendNotifyMessage ((HWND)pWin, MSG_VSCROLL, SB_ENDSCROLL, 0);
SetAutoRepeatMessage (HWND_DESKTOP, 0, 0, 0);
}
downPos = SBPOS_UNKNOWN;
movePos = SBPOS_UNKNOWN;
break;
case MSG_NCMOUSEMOVE:
if (sbCode == SB_THUMBTRACK && downPos == SBPOS_THUMB) {
newBarStart = oldBarStart + y - oldy;
newThumbPos = newBarStart
* (pWin->vscroll.maxPos - pWin->vscroll.minPos + 1)
/ (rcBar.bottom - rcBar.top) + pWin->vscroll.minPos;
if (newThumbPos != oldThumbPos
&& newThumbPos >= pWin->vscroll.minPos
&& newThumbPos <= pWin->vscroll.maxPos) {
SendNotifyMessage ((HWND)pWin,
MSG_VSCROLL, SB_THUMBTRACK, newThumbPos);
oldThumbPos = newThumbPos;
}
movePos = curPos;
break;
}
if (movePos == downPos && curPos != downPos)
sbUpButton (pWin, downPos);
else if (movePos != downPos && curPos == downPos)
sbDownButton (pWin, downPos);
movePos = curPos;
break;
}
return TRUE;
}
//计算滚动条滑块大小和位置。
static void wndScrollBarPos (PMAINWIN pWin, BOOL bIsHBar, RECT* rcBar)
{
UINT moveRange;
PSCROLLBARINFO pSBar;
if (bIsHBar)
{
pSBar = &pWin->hscroll;
}
else
{
pSBar = &pWin->vscroll;
}
//若滚动区间为空,则隐藏滚动条.
if (pSBar->minPos == pSBar->maxPos)
{
pSBar->status |= SBS_HIDE;
return;
}
//计算滚动条可用区域(即滚动滑块可以滑动的区间象素个数)
if (bIsHBar)
{
moveRange = RECTWP (rcBar) - (GetMainWinMetrics (MWM_CXHSCROLL)<<1);
}
else
{
moveRange = RECTHP (rcBar) - (GetMainWinMetrics (MWM_CYVSCROLL)<<1);
}
//若页面间隔为0,则取默认滚动滑块长度为当前滑块长度,并进行合法性修正.
if (pSBar->pageStep == 0)
{
pSBar->barLen = GetMainWinMetrics (MWM_DEFBARLEN);
if (pSBar->barLen > moveRange)
{
pSBar->barLen = GetMainWinMetrics (MWM_MINBARLEN);
}
}
/*
否则,计算滚动滑块大小.并对合法性进行修正.
计算方程: 每滚动间隔对应象素大小为 moveRange / ScrollRange ;
pageStep:每页大小即控件能显示的区域,所对应的滚动条滚动间隔数.
ScrollRange - PageStep, 就是滚动条的逻辑活动的范围.
对应于 moveRange - barLen 就是滚动条能滚定的象素范围.即一一对应关系.
那么滚动条滑块的长度就是 PageStep 对应的象素大小.
-> pSBar->barLen = moveRange * PageStep / ScrollRange ;
ScrollRange = pSBar->maxPos - pSBar->minPos ;
(滚动范围以0为开始, 如 0 - 99 表示 100 个滚动范围)
(若以 1 开始, 则出错 因为 1 - 99 才99 个滚动范围).
"+ 0.5" 是四舍五入的方法。便于取整.
*/
else
{
pSBar->barLen = (int) (moveRange*pSBar->pageStep * 1.0f/
(pSBar->maxPos - pSBar->minPos + 1) + 0.5);
/*
修正合法值.
*/
if (pSBar->barLen < GetMainWinMetrics (MWM_MINBARLEN))
{
pSBar->barLen = GetMainWinMetrics (MWM_MINBARLEN);
}
}
/*
计算滚动滑块开始位置.
计算方程: BarStart = PixelPerScrollGap * CurScrollRange ;
= moveRange * CurScrollRange / ScrollRange ;
即开始位置为每逻辑滚动间隔对应象素大小*当前逻辑滚动间隔 ;
ScrollRange = pSBar->maxPos - pSBar->minPos ;
(滚动范围以0为开始, 如 0 - 99 表示 100 个滚动范围)
(若以 1 开始, 则出错 因为 1 - 99 才99 个滚动范围).
"+ 0.5" 是四舍五入的方法。便于取整.
*/
pSBar->barStart = (int) (moveRange*(pSBar->curPos - pSBar->minPos) * 1.0f/
(pSBar->maxPos - pSBar->minPos + 1) + 0.5);
/*
修正非法值。
*/
if (pSBar->barStart + pSBar->barLen > moveRange)
{
pSBar->barStart = moveRange - pSBar->barLen;
}
if (pSBar->barStart < 0)
{
pSBar->barStart = 0;
}
}
//计算垂直滚动条矩形区域.
static BOOL wndGetVScrollBarRect (const MAINWIN* pWin,
RECT* rcVBar)
{
if (pWin->dwStyle & WS_VSCROLL)
{
//取边界宽度
int iBorder = wndGetBorder (pWin);
//计算滚动条左边和右边
rcVBar->left = pWin->right - GetMainWinMetrics (MWM_CXVSCROLL) - iBorder;
rcVBar->right = pWin->right - iBorder;
//计算矩形顶点和底边
#ifdef _FLAT_WINDOW_STYLE
rcVBar->top = pWin->ct - 1;
#else
rcVBar->top = pWin->ct;
#endif
rcVBar->bottom = pWin->bottom - iBorder;
//若存在水平滚动条,则减去水平滚动条高度
if (pWin->dwStyle & WS_HSCROLL && !(pWin->hscroll.status & SBS_HIDE))
{
rcVBar->bottom -= GetMainWinMetrics (MWM_CYHSCROLL);
}
#ifdef _FLAT_WINDOW_STYLE
if (iBorder > 0)
OffsetRect (rcVBar, 1, 0);
#endif
return TRUE;
}
return FALSE;
}
//计算水平滚动条矩形区域.与垂直情况相似
static BOOL wndGetHScrollBarRect (const MAINWIN* pWin,
RECT* rcHBar)
{
if (pWin->dwStyle & WS_HSCROLL) {
int iBorder = wndGetBorder (pWin);
rcHBar->top = pWin->bottom - GetMainWinMetrics (MWM_CYHSCROLL)
- iBorder;
rcHBar->bottom = pWin->bottom - iBorder;
#ifdef _FLAT_WINDOW_STYLE
rcHBar->left = pWin->cl - 1;
#else
rcHBar->left = pWin->cl;
#endif
rcHBar->right = pWin->right - iBorder;
if (pWin->dwStyle & WS_VSCROLL && !(pWin->vscroll.status & SBS_HIDE))
rcHBar->right -= GetMainWinMetrics (MWM_CXVSCROLL);
#ifdef _FLAT_WINDOW_STYLE
if (iBorder > 0)
OffsetRect (rcHBar, 0, 1);
#endif
return TRUE;
}
return FALSE;
}
//计算点击垂直滚动条上逻辑位置分类.
static int wndGetVScrollBarPos (PMAINWIN pWin, int x, int y)
{
RECT rcBar;
RECT rcArea;
if (pWin->vscroll.status & SBS_DISABLED)
{
return SBPOS_UNKNOWN;
}
//获取垂直滚动条矩形区域.
wndGetVScrollBarRect (pWin, &rcBar);
//若点不再矩形区域内,则返回空.
if (!PtInRect (&rcBar, x, y))
{
return SBPOS_UNKNOWN;
}
rcArea.left = rcBar.left;
rcArea.right = rcBar.right;
//是否为顶部的按钮.
// Left arrow area
rcArea.top = rcBar.top;
rcArea.bottom = rcArea.top + GetMainWinMetrics (MWM_CYVSCROLL);
if (PtInRect (&rcArea, x, y))
{
return SBPOS_UPARROW;
}
//是否为底部的按钮.
// Right arrow area
rcArea.top = rcBar.bottom - GetMainWinMetrics (MWM_CYVSCROLL);
rcArea.bottom = rcBar.bottom;
if (PtInRect (&rcArea, x, y))
{
return SBPOS_DOWNARROW;
}
//是否在滑块上边
if (y < (rcBar.top + pWin->vscroll.barStart
+ GetMainWinMetrics (MWM_CYVSCROLL)))
return SBPOS_UPSPACE;
//是否为滑块下边
if (y > (rcBar.top + pWin->vscroll.barStart + pWin->vscroll.barLen
+ GetMainWinMetrics (MWM_CYVSCROLL)))
return SBPOS_DOWNSPACE;
//在滑块上
return SBPOS_THUMB;
}
//计算点击水平滚动条上逻辑位置分类.与垂直情况类似。
static int wndGetHScrollBarPos (PMAINWIN pWin, int x, int y)
{
RECT rcBar;
RECT rcArea;
if (pWin->hscroll.status & SBS_DISABLED)
return SBPOS_UNKNOWN;
wndGetHScrollBarRect (pWin, &rcBar);
if (!PtInRect (&rcBar, x, y))
return SBPOS_UNKNOWN;
rcArea.top = rcBar.top;
rcArea.bottom = rcBar.bottom;
// Left arrow area
rcArea.left = rcBar.left;
rcArea.right = rcArea.left + GetMainWinMetrics (MWM_CXHSCROLL);
if (PtInRect (&rcArea, x, y))
return SBPOS_LEFTARROW;
// Right arrow area
rcArea.left = rcBar.right - GetMainWinMetrics (MWM_CXHSCROLL);
rcArea.right = rcBar.right;
if (PtInRect (&rcArea, x, y))
return SBPOS_RIGHTARROW;
if (x < (rcBar.left + pWin->hscroll.barStart
+ GetMainWinMetrics (MWM_CXHSCROLL)))
return SBPOS_LEFTSPACE;
if (x > (rcBar.left + pWin->hscroll.barStart + pWin->hscroll.barLen
+ GetMainWinMetrics (MWM_CXHSCROLL)))
return SBPOS_RIGHTSPACE;
return SBPOS_THUMB;
}
//获取滚动条信息结构
static PSCROLLBARINFO wndGetScrollBar (MAINWIN* pWin, int iSBar)
{
//水平
if (iSBar == SB_HORZ)
{
if (pWin->dwStyle & WS_HSCROLL)
{
return &pWin->hscroll;
}
}
//垂直
else if (iSBar == SB_VERT)
{
if (pWin->dwStyle & WS_VSCROLL)
{
return &pWin->vscroll;
}
}
return NULL;
}
//设置滚动条是否可用,与设置滚动条是否可见的逻辑相似
BOOL GUIAPI EnableScrollBar (HWND hWnd, int iSBar, BOOL bEnable)
{
PSCROLLBARINFO pSBar;
PMAINWIN pWin;
BOOL bPrevState;
RECT rcBar;
pWin = (PMAINWIN)hWnd;
if ( !(pSBar = wndGetScrollBar (pWin, iSBar)) )
{
return FALSE;
}
bPrevState = !(pSBar->status & SBS_DISABLED);
if (bEnable && !bPrevState)
{
pSBar->status &= ~SBS_DISABLED;
}
else if (!bEnable && bPrevState)
{
pSBar->status |= SBS_DISABLED;
}
else
{
return FALSE;
}
if (iSBar == SB_VERT)
{
wndGetVScrollBarRect (pWin, &rcBar);
}
else
{
wndGetHScrollBarRect (pWin, &rcBar);
}
rcBar.left -= pWin->left;
rcBar.top -= pWin->top;
rcBar.right -= pWin->left;
rcBar.bottom -= pWin->top;
SendAsyncMessage (hWnd, MSG_NCPAINT, 0, (LPARAM)(&rcBar));
return TRUE;
}
//获取滚动条逻辑滚动位置
BOOL GUIAPI GetScrollPos (HWND hWnd, int iSBar, int* pPos)
{
PSCROLLBARINFO pSBar;
PMAINWIN pWin;
pWin = (PMAINWIN)hWnd;
if ( !(pSBar = wndGetScrollBar (pWin, iSBar)) )
{
return FALSE;
}
*pPos = pSBar->curPos;
return TRUE;
}
//获取滚动条逻辑滚动范围。
BOOL GUIAPI GetScrollRange (HWND hWnd, int iSBar, int* pMinPos, int* pMaxPos)
{
PSCROLLBARINFO pSBar;
PMAINWIN pWin;
pWin = (PMAINWIN)hWnd;
if ( !(pSBar = wndGetScrollBar (pWin, iSBar)) )
{
return FALSE;
}
*pMinPos = pSBar->minPos;
*pMaxPos = pSBar->maxPos;
return TRUE;
}
//设置滚动条当前逻辑滚动位置,与设置滚动条滚动信息类似
BOOL GUIAPI SetScrollPos (HWND hWnd, int iSBar, int iNewPos)
{
PSCROLLBARINFO pSBar;
PMAINWIN pWin;
RECT rcBar;
pWin = (PMAINWIN)hWnd;
if ( !(pSBar = wndGetScrollBar (pWin, iSBar)) )
{
return FALSE;
}
if (iNewPos < pSBar->minPos)
{
pSBar->curPos = pSBar->minPos;
}
else
{
pSBar->curPos = iNewPos;
}
if(1)
{
int max = pSBar->maxPos;
max -= ((pSBar->pageStep - 1) > 0)?(pSBar->pageStep - 1):0;
if (pSBar->curPos > max)
pSBar->curPos = max;
}
if (iSBar == SB_VERT)
{
wndGetVScrollBarRect (pWin, &rcBar);
}
else
{
wndGetHScrollBarRect (pWin, &rcBar);
}
rcBar.left -= pWin->left;
rcBar.top -= pWin->top;
rcBar.right -= pWin->left;
rcBar.bottom -= pWin->top;
wndScrollBarPos (pWin, iSBar == SB_HORZ, &rcBar);
if (iSBar == SB_VERT)
{
rcBar.top += GetMainWinMetrics (MWM_CYVSCROLL);
rcBar.bottom -= GetMainWinMetrics (MWM_CYVSCROLL);
}
else
{
rcBar.left += GetMainWinMetrics (MWM_CXHSCROLL);
rcBar.right -= GetMainWinMetrics (MWM_CXHSCROLL);
}
SendAsyncMessage (hWnd, MSG_NCPAINT, 0, (LPARAM)(&rcBar));
return TRUE;
}
/*
设置滚动条逻辑滚动范围,与设置滚动条滚动信息类似
*/
BOOL GUIAPI SetScrollRange (HWND hWnd, int iSBar, int iMinPos, int iMaxPos)
{
PSCROLLBARINFO pSBar;
PMAINWIN pWin;
RECT rcBar;
pWin = (PMAINWIN)hWnd;
if ( !(pSBar = wndGetScrollBar (pWin, iSBar)) )
{
return FALSE;
}
pSBar->minPos = (iMinPos < iMaxPos)?iMinPos:iMaxPos;
pSBar->maxPos = (iMinPos > iMaxPos)?iMinPos:iMaxPos;
// validate parameters.
if (pSBar->curPos < pSBar->minPos)
{
pSBar->curPos = pSBar->minPos;
}
if (pSBar->pageStep <= 0)
{
pSBar->pageStep = 0;
}
else if (pSBar->pageStep > (pSBar->maxPos - pSBar->minPos + 1))
{
pSBar->pageStep = pSBar->maxPos - pSBar->minPos + 1;
}
if(1)
{
int max = pSBar->maxPos;
max -= ((pSBar->pageStep - 1) > 0)?(pSBar->pageStep - 1):0;
if (pSBar->curPos > max)
{
pSBar->curPos = max;
}
}
if (iSBar == SB_VERT)
{
wndGetVScrollBarRect (pWin, &rcBar);
}
else
{
wndGetHScrollBarRect (pWin, &rcBar);
}
rcBar.left -= pWin->left;
rcBar.top -= pWin->top;
rcBar.right -= pWin->left;
rcBar.bottom -= pWin->top;
wndScrollBarPos (pWin, iSBar == SB_HORZ, &rcBar);
if (iSBar == SB_VERT)
{
rcBar.top += GetMainWinMetrics (MWM_CYVSCROLL);
rcBar.bottom -= GetMainWinMetrics (MWM_CYVSCROLL);
}
else
{
rcBar.left += GetMainWinMetrics (MWM_CXHSCROLL);
rcBar.right -= GetMainWinMetrics (MWM_CXHSCROLL);
}
SendAsyncMessage (hWnd, MSG_NCPAINT, 0, (LPARAM)(&rcBar));
return TRUE;
}
//设置滚动条信息
BOOL GUIAPI SetScrollInfo (HWND hWnd, int iSBar,
const SCROLLINFO* lpsi, BOOL fRedraw)
{
PSCROLLBARINFO pSBar;
PMAINWIN pWin;
RECT rcBar;
pWin = (PMAINWIN)hWnd;
//找到滚动条信息。
if ( !(pSBar = wndGetScrollBar (pWin, iSBar)) )
{
return FALSE;
}
//设置滚定区间大小
if( lpsi->fMask & SIF_RANGE )
{
pSBar->minPos = (lpsi->nMin < lpsi->nMax)?lpsi->nMin:lpsi->nMax;
pSBar->maxPos = (lpsi->nMin < lpsi->nMax)?lpsi->nMax:lpsi->nMin;
}
//设置滚动位置
if( lpsi->fMask & SIF_POS )
{
pSBar->curPos = lpsi->nPos;
}
//设置滚动页面大小.
if( lpsi->fMask & SIF_PAGE )
{
pSBar->pageStep = lpsi->nPage;
}
//矫正非法数据.
// validate parameters.
if (pSBar->curPos < pSBar->minPos)
{
pSBar->curPos = pSBar->minPos;
}
//计算页面大小.
if (pSBar->pageStep <= 0)
{
pSBar->pageStep = 0;
}
else if (pSBar->pageStep > (pSBar->maxPos - pSBar->minPos + 1))
{
pSBar->pageStep = pSBar->maxPos - pSBar->minPos + 1;
}
/*
重新计算滚动滑块的逻辑位置. 若PageSize增大, 则滑块可滚动的逻辑区域会变小,
所以需要修正滑块的当前逻辑位置.
*/
if(1)
{
int max = pSBar->maxPos;
/*
滑块的可滚动区域。
*/
max -= ((pSBar->pageStep - 1) > 0)?(pSBar->pageStep - 1):0;
if (pSBar->curPos > max)
{
pSBar->curPos = max;
}
}
//重绘滚动条
if(fRedraw)
{
//获取滚动条矩形区域(相对于窗口原点坐标)
if (iSBar == SB_VERT)
{
wndGetVScrollBarRect (pWin, &rcBar);
}
else
{
wndGetHScrollBarRect (pWin, &rcBar);
}
rcBar.left -= pWin->left;
rcBar.top -= pWin->top;
rcBar.right -= pWin->left;
rcBar.bottom -= pWin->top;
//计算滚动条滑块大小和位置.
wndScrollBarPos (pWin, iSBar == SB_HORZ, &rcBar);
//重绘滚动条.
if (iSBar == SB_VERT)
{
rcBar.top += GetMainWinMetrics (MWM_CYVSCROLL);
rcBar.bottom -= GetMainWinMetrics (MWM_CYVSCROLL);
}
else
{
rcBar.left += GetMainWinMetrics (MWM_CXHSCROLL);
rcBar.right -= GetMainWinMetrics (MWM_CXHSCROLL);
}
SendAsyncMessage (hWnd, MSG_NCPAINT, 0, (LPARAM)(&rcBar));
}
return TRUE;
}
// 获取滚动条信息.
BOOL GUIAPI GetScrollInfo(HWND hWnd, int iSBar, PSCROLLINFO lpsi)
{
PSCROLLBARINFO pSBar;
PMAINWIN pWin;
pWin = (PMAINWIN)hWnd;
//找到滚动条
if (!(pSBar = wndGetScrollBar (pWin, iSBar)))
{
return FALSE;
}
//逻辑滚动区间大小
if (lpsi->fMask & SIF_RANGE)
{
lpsi->nMin = pSBar->minPos;
lpsi->nMax = pSBar->maxPos;
}
//当前滑块逻辑位置
if (lpsi->fMask & SIF_POS)
{
lpsi->nPos = pSBar->curPos;
}
//滚动页大小,即窗口显示内容所占的逻辑滚动数.
if (lpsi->fMask & SIF_PAGE)
{
lpsi->nPage = pSBar->pageStep;
}
return TRUE;
}
//显示滚动条.
BOOL GUIAPI ShowScrollBar (HWND hWnd, int iSBar, BOOL bShow)
{
PSCROLLBARINFO pSBar;
PMAINWIN pWin;
BOOL bPrevState;
RECT rcBar;
pWin = (PMAINWIN)hWnd;
//获取滚动条信息。
if ( !(pSBar = wndGetScrollBar (pWin, iSBar)) )
{
return FALSE;
}
//前一状态是否为显示状态.(包括disbale,mormal);
bPrevState = !(pSBar->status & SBS_HIDE);
//若前一状态为隐藏,且当前命令为显示命令.则修改当前状态为非隐藏状态.
if (bShow && !bPrevState)
{
pSBar->status &= ~SBS_HIDE;
}
//若前一状态为显示状态,且当前命令为隐藏命令,则隐藏.
else if (!bShow && bPrevState)
{
pSBar->status |= SBS_HIDE;
}
//否则,前一状态与命令状态相同,直接返回.(FALSE???返回失败)
else
{
return FALSE;
}
//重新计算非客户区.
SendAsyncMessage (hWnd, MSG_CHANGESIZE, 0, 0);
//获取滚动条位置.
if (iSBar == SB_VERT)
{
wndGetVScrollBarRect (pWin, &rcBar);
}
else
{
wndGetHScrollBarRect (pWin, &rcBar);
}
//扩大2象素(left--,top--,right++,bottom++)
InflateRect (&rcBar, 1, 1);
//重新计算客户区.
RecalcClientArea (hWnd);
//非客户区重绘.
if (bShow)
{
//若为显示滚动条,则直接发送重绘消息.此时没有重绘客户区.
SendAsyncMessage (hWnd, MSG_NCPAINT, 0, 0);
}
else
{
//若隐藏滚动条,则重绘非客户区,并重绘客户区(滚动条相对对于客户区坐标原点的矩形区域).
rcBar.left -= pWin->cl;
rcBar.top -= pWin->ct;
rcBar.right -= pWin->cl;
rcBar.bottom -= pWin->ct;
SendAsyncMessage (hWnd, MSG_NCPAINT, 0, 0);
InvalidateRect (hWnd, &rcBar, TRUE);
}
return TRUE;
}