I will only explain about the vertical bar.
The scrollbar does not scroll the window. It is a control that takes care of drawing itself en notify via the WindowProc with a WM_VSCROLL, when an event has happened and what has happened. What is going to be done with the WM_VSCROLL message and its data is up to the programmer so the scrollbar could be used for other things as well.
For bookkeeping a standard scrollbar's state the SCROLLINFO structure is used, together with the GetScrollInfo() and SetScrollInfo() functions.
The nice thing build in is that you can set for a amounth to scroll with SetScrollInfo(), while internally it checks and especially, it corrects the scroll amounth to the amounth that scrolling is allowed. Then, with a GetScrollInfo() call right behind it you retrieve the amounth allowed to scroll. It could be nothing, when already at the bottom of document, or only partially after a page down, when only half a page was left.
Here is how a WM_VSCROLL message can be implemented.
The v structure contains our own scrolling related variables. I have taken the code from a window containing class in which v is contained, but further the code should be correct.
[tt]
case WM_VSCROLL:
si.cbSize = sizeof(SCROLLINFO); //(1)
si.fMask = SIF_ALL;
GetScrollInfo(hWnd, SB_VERT, &si);
v.cyPos = si.nPos; //(2)
switch(LOWORD(wParam)){ //(3)
case SB_TOP: si.nPos = si.nMin; break;
case SB_BOTTOM: si.nPos = si.nMax; break;
case SB_LINEUP: si.nPos -= 1; break;
case SB_LINEDOWN: si.nPos += 1; break;
case SB_PAGEUP: si.nPos -= si.nPage; break;
case SB_PAGEDOWN: si.nPos += si.nPage; break;
case SB_THUMBTRACK: si.nPos = si.nTrackPos; break;
}
si.fMask = SIF_POS; //(4)
SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
GetScrollInfo(hWnd, SB_VERT, &si);
if(si.nPos != v.cyPos){ //(5)
ScrollWindow(hWnd, NC, (si.nPos - v.cyPos) * v.cyUni, NULL, NULL);
v.cyPos = si.nPos;
}
break;
/* COMMENTS:
//A scroll request arrives from the scrollbar
1. Get current scroll info
2. update our own variable with latest data
3. Translate scroll event to amounth to scroll
4. Suggest the scroll and get the corrected data
5. A position change is allowed/made in the bookkeeping;
perform the actual scroll and update our own variable
*/
[/tt]
That's it for the WM_VSCROLL message. Note that if your document or window contains child windows, ScrollWindow() will automatically move them in sync with where they visual appear after the scroll bitblit, unless your window was made with the CS_OWNDC style. If you like/need to control this yourself look at the ScrollDC() function.
When the window its size changes or the document size changes, the SCROLLINFO structure needs updating. Because same things need to be performed I've put the code inside one function that can be called whenever there's a update needed. The function will scroll the window when needed, for example when the document is scrolled till bottom and then the Y-size is increased.
Before calling this function it is important to update our v.vars first with the new scroll settings.
[tt]
void MyUpdateScrollInfo()
{
si.cbSize = sizeof(SCROLLINFO); //(1)
si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
si.nMin = 0;
si.nMax = (v.cyDoc / v.cyUni) - 1; //(2)
si.nPage = v.cyWin / v.cyUni;
si.nPos = v.cyPos;
SetScrollInfo(hwnd, SB_VERT, &si, TRUE); //(3)
GetScrollInfo(hwnd, SB_VERT, &si);
if(si.nPos != v.cyPos){ //(4)
ScrollWindow(hWnd, NC, (si.nPos - v.cyPos) * v.cyUni, NULL, NULL);
v.cyPos = si.nPos;
}
}
/* COMMENTS:
1. Prepare the structure and announce what needs update
2. Set the possible changes document-, scrollunit- and window size,
and current scroll position.
3. Set the info and receive the checked and corrected data
4. scroll if needed and update v.var
*/
[/tt]
That's it for updating the scroll info. Call the function from the following code situations...
[tt]
case WM_SIZE:
v.cxWin = LOWORD(lParam);
v.cyWin = HIWORD(lParam);
zUpdateScrollInfo();
break;
case WM_MOVE:
v.oxWin = LOWORD(lParam);
v.oyWin = HIWORD(lParam);
break;
void SetDocumentSize(long cx, long cy)
{
v.cxDoc = max(1, cx); //(1)
v.cyDoc = max(1, cy);
MyUpdateScrollInfo();
}
void SetScrollUnits(long cx, long cy)
{
v.cxUni = max(1, cx);
v.cyUni = max(1, cy);
MyUpdateScrollInfo();
}
void SetWindowDim(long ox, long oy, long cx, long cy) //(2)
{
MoveWindow(hwnd, ox, oy, max(1, cx), max(1, cy), FALSE);
}
/*COMMENTS:
1. Minimum 1, to prevent divide by zero errors
2. If difference coords, will result in WM_SIZE and/or WM_MOVE message
*/
[/tt]
Few! got that? =)
Goodluck!