MINIGUI源码分析(1) ------ 滚动条管理分析

 

http://xuyacao.bokee.com/3753615.html
http://blog.chinaunix.net/space.php?uid=9563036&do=blog&id=352405
                                      

//水平滚动条消息处理
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;
   
}


你可能感兴趣的:(MiniGUI)