ScrollbarsLib:
;---------------------------------------------------------
; Scrollbar lib is small library that provides
; windows with client area bigger than its actual size.
;---------------------------------------------------------

;----------------------------------------------------------------------
; This procedure is handler for WM_HSCROLL and WM_VSCROLL
; messages. Call it from window message procedure passing
; the message parameters.
;----------------------------------------------------------------------
proc ScrollBarMessage, .hwnd, .wmsg, .wparam, .updateproc
.sbi SCROLLINFO
.kind dd ?
begin
        mov    eax, [.wmsg]
        sub    eax, WM_HSCROLL
        mov    [.kind], eax

        lea    edi, [.sbi]

        mov     [.sbi.cbSize], sizeof.SCROLLINFO
        mov     [.sbi.fMask], SIF_RANGE or SIF_PAGE or SIF_POS
        invoke  GetScrollInfo, [.hwnd], [.kind], edi

        movzx   ebx, word [.wparam]
        cmp     ebx, SB_THUMBTRACK
        je      .track
        cmp     ebx, SB_THUMBPOSITION
        je      .track

        cmp     ebx, SB_TOP
        je      .top
        cmp     ebx, SB_BOTTOM
        je      .bottom

        mov     edx, 1  ; multiplier down

        cmp     ebx, SB_PAGEDOWN
        je      .pageupdn
        cmp     ebx, SB_LINEDOWN
        je      .lineupdn

        mov     edx, -1  ; multiplier UP

        cmp     ebx, SB_PAGEUP
        je      .pageupdn
        cmp     ebx, SB_LINEUP
        je      .lineupdn
; Undefined command...
        return

;-----------------------------------------------------
; Handling of different actions...
;-----------------------------------------------------
.track:
        movsx   eax, word [.wparam+2]
        jmp     .setpos

.top:
        mov     eax, [.sbi.nMin]
        jmp     .setpos

.bottom:
        mov     eax, [.sbi.nMax]
        sub     eax, [.sbi.nPage]
        jmp     .setpos

.pageupdn:
        mov     eax, [.sbi.nPos]
        mov     ecx, [.sbi.nPage]
        imul    ecx, edx
        add     eax, ecx
        jmp     .setpos

.lineupdn:
        mov     eax, [.sbi.nPos]
        mov     ecx, [.sbi.nPage]
        sar     ecx, 4
        jnz     @f
        inc     ecx
@@:
        imul    ecx, edx
        add     eax, ecx

.setpos:
        mov     esi, [.sbi.nPos] ; Old scroll position.

        mov     [.sbi.nPos], eax ; New scroll position.
        mov     [.sbi.fMask], SIF_POS
        invoke  SetScrollInfo, [.hwnd], [.kind], edi, TRUE

; Update children windows positions
        mov     [.sbi.fMask], SIF_POS
        invoke  GetScrollInfo, [.hwnd], [.kind], edi ; get the position corrected by Windows

        sub     esi, [.sbi.nPos] ; correction value
        stdcall [.updateproc], [.hwnd], [.kind], esi
        return
endp



;--------------------------------------------------------------------
; Call this procedure when the window size have been changed, to
; adjust scrollbars thumbs size acordingly.
;--------------------------------------------------------------------
proc UpdateThumbs, .hwnd
.rect RECT
begin
        lea     eax, [.rect]
        invoke  GetClientRect, [.hwnd], eax
        stdcall _DoUpdateOneThumb, [.hwnd], SB_HORZ, [.rect.right]
        stdcall _DoUpdateOneThumb, [.hwnd], SB_VERT, [.rect.bottom]
        return
endp



proc _DoUpdateOneThumb, .hwnd, .kind, .size
.sbi SCROLLINFO
begin
; Get the current possition of the scrollbar.
        mov     [.sbi.cbSize], sizeof.SCROLLINFO
        mov     [.sbi.fMask], SIF_POS
        lea     eax, [.sbi]
        invoke  GetScrollInfo, [.hwnd], [.kind], eax
        mov     esi, [.sbi.nPos] ; Old position of the scrollbar

; Set the new page size of the scrollbar.
        mov     eax, [.size]
        mov     [.sbi.nPage], eax
        mov     [.sbi.fMask], SIF_PAGE
        lea     eax, [.sbi]
        invoke  SetScrollInfo, [.hwnd], [.kind], eax, TRUE

; Get again the new position, because possibly Windows changed it.
        mov     [.sbi.fMask], SIF_POS
        lea     eax, [.sbi]
        invoke  GetScrollInfo, [.hwnd], [.kind], eax

; Move the first level children acording to the new scroll position.
        sub     esi, [.sbi.nPos]  ; correction value
        jz      .finish
        stdcall DoCorrectChildren, [.hwnd], [.kind], esi
.finish:
        return
endp


proc DoCorrectChildren, .hwnd, .kind, .correct
.defer dd ?
.rect  RECT
begin
        mov     edi, [.kind]
        shl     edi, 2          ; eax = 0 if .kind = SB_HORZ (0) and eax = 4 if .kind = SB_VERT (1)
        mov     esi, [.correct]

        invoke  BeginDeferWindowPos, 10
        mov     [.defer], eax

        invoke  GetWindow, [.hwnd], GW_CHILD
.loop:
        test    eax, eax
        je      .enddefer

        mov     ebx, eax

        lea     eax, [.rect]
        invoke  GetWindowRect, ebx, eax

        lea     eax, [.rect]
        invoke  ScreenToClient, [.hwnd], eax

        add     [.rect+edi], esi
        invoke  DeferWindowPos, [.defer], ebx, 0, [.rect.left], [.rect.top], 0, 0, SWP_NOSIZE or SWP_NOZORDER
        mov     [.defer], eax

        invoke  GetWindow, ebx, GW_HWNDNEXT
        jmp     .loop

.enddefer:
        invoke  EndDeferWindowPos, [.defer]
        return
endp




proc AutoSizeScrollers, .hwnd
.sbi SCROLLINFO
.rect RECT
.maxrect RECT
begin
        mov     eax, $7fffffff
        mov     [.maxrect.left], eax
        mov     [.maxrect.top], eax
        inc     eax
        mov     [.maxrect.right], eax
        mov     [.maxrect.bottom], eax

        invoke  GetWindow, [.hwnd], GW_CHILD

.loop:
        test    eax, eax
        jz      .endloop
        mov     ebx, eax

        lea     esi, [.rect]
        invoke  GetWindowRect, ebx, esi
        invoke  ScreenToClient, [.hwnd], esi
        lea     eax, [esi+8]
        invoke  ScreenToClient, [.hwnd], eax

        mov     eax, [.rect.left]
        cmp     eax, [.maxrect.left]
        jge     @f
        mov     [.maxrect.left], eax
@@:
        mov     eax, [.rect.top]
        cmp     eax, [.maxrect.top]
        jge     @f
        mov     [.maxrect.top], eax
@@:
        mov     eax, [.rect.right]
        cmp     eax, [.maxrect.right]
        jle     @f
        mov     [.maxrect.right], eax
@@:
        mov     eax, [.rect.bottom]
        cmp     eax, [.maxrect.bottom]
        jle     @f
        mov     [.maxrect.bottom], eax
@@:
        invoke  GetWindow, ebx, GW_HWNDNEXT
        jmp     .loop

.endloop:
        mov     eax, [.maxrect.left]
        mov     ecx, [.maxrect.right]

        mov     [.sbi.nMin], 0
        mov     [.sbi.nMax], ecx
        mov     [.sbi.fMask], SIF_RANGE
        mov     [.sbi.cbSize], sizeof.SCROLLINFO
        lea     eax, [.sbi]
        invoke  SetScrollInfo, [.hwnd], SB_HORZ, eax, TRUE

        mov     eax, [.maxrect.top]
        mov     ecx, [.maxrect.bottom]

        mov     [.sbi.nMin], 0
        mov     [.sbi.nMax], ecx
        lea     eax, [.sbi]
        invoke  SetScrollInfo, [.hwnd], SB_VERT, eax, TRUE

        return
endp


DispSize 'Scrollbars library:', $-ScrollbarsLib