; _______________________________________________________________________________________
;|                                                                                       |
;| ..::FreshLib::..  Free, open source. Licensed under "BSD 2-clause" license."          |
;|_______________________________________________________________________________________|
;
;  Description: TScrollWindow object class
;
;  Target OS: Any
;
;  Dependencies:
;
;  Notes: TScrollWindow is window that may have scrollers to scroll the client area.
;_________________________________________________________________________________________
module "TScrollWindow library"


sbkHorizontal = 0
sbkVertical = 1


object TScrollbar, TWindow

  ._pos  dd ?
  ._page dd ?
  ._max  dd ?

  ._kind dd ?

  ._drag_ofs dd ?

  ._state  dd ?

  param .Kind, ._kind, .SetKind

  param .Pos, ._pos, .SetPos
  param .Page, ._page, .SetPage
  param .Max, ._max, .SetMax

  method .SetKind, .value

  method .SetPos, .value
  method .SetPage, .value
  method .SetMax, .value

  method .Paint

  method .EventMouseMove, .x, .y, .kbdState

  method .EventButtonPress, .button, .kbdState, .x, .y
  method .EventButtonRelease, .button, .kbdState, .x, .y

  method .EventMouseEnter
  method .EventMouseLeave
endobj



;_________________________________________________________________________________________


method TScrollbar.SetKind         ;, .value
begin
        mov     eax, [.self]
        push    [.value]
        pop     [eax+TScrollbar._kind]

        exec    eax, TScrollbar:Refresh
        return
endp

;_________________________________________________________________________________________

method TScrollbar.SetPos          ;, .value
begin
        push    eax ecx

        mov     ecx, [.self]

        mov     eax, [.value]
        cmp     eax, [ecx+TScrollbar._pos]
        je      .finish

        mov     [ecx+TScrollbar._pos], eax
        exec    ecx, TScrollbar:Refresh

.finish:
        pop     ecx eax
        return
endp

;_________________________________________________________________________________________


method TScrollbar.SetPage         ;, .value
begin
        push    eax ecx

        mov     ecx, [.self]

        mov     eax, [.value]
        cmp     eax, [ecx+TScrollbar._page]
        je      .finish

        mov     [ecx+TScrollbar._page], eax
        exec    ecx, TScrollbar:Refresh

.finish:
        pop     ecx eax
        return
endp


;_________________________________________________________________________________________


method TScrollbar.SetMax          ;, .value
begin
        push    eax ecx

        mov     ecx, [.self]

        mov     eax, [.value]
        cmp     eax, [ecx+TScrollbar._max]
        je      .finish

        mov     [ecx+TScrollbar._max], eax

        test    eax, eax
        setg    al
        movzx   eax, al

        set     ecx, TScrollbar:Visible, eax
        exec    ecx, TScrollbar:Refresh

.finish:
        pop     ecx eax
        return
endp



;_________________________________________________________________________________________


method TScrollbar.Paint
.rect  TBounds
begin
        pushad
        mov     esi, [.self]
        mov     ebx, [esi+TWindow._canvas]
        test    ebx, ebx
        jz      .finish

        xor     eax, eax
        mov     ecx, [esi+TScrollbar._width]
        mov     edx, [esi+TScrollbar._height]

        mov     [.rect.x], eax
        mov     [.rect.y], eax
        mov     [.rect.width], ecx
        mov     [.rect.height], edx

        mov     edi, [esi+TScrollbar._state]

        stdcall DrawSolidRect, ebx, eax, eax, [esi+TScrollbar._width], [esi+TScrollbar._height], [GUI.clScrollBk+4*edi]

        mov     ecx, [esi+TScrollbar._kind]
        mov     edx, [esi+TScrollbar._width + 4*ecx]    ; sbkHorizontal = 0; sbkVertical = 1

        stdcall _SliderPixels, esi, edx

        mov     [.rect.x + 4*ecx], eax
        mov     [.rect.width + 4*ecx], edx

        stdcall DrawSolidRect, ebx, [.rect.x], [.rect.y], [.rect.width], [.rect.height], [GUI.clScrollSlider+4*edi]

        mov     eax, [.rect.width]
        add     eax, [.rect.x]
        jle     .finish

        mov     edx, [.rect.height]
        add     edx, [.rect.y]
        jle     .finish

        stdcall DrawScrollerEdge, ebx, eax, edx, ecx, [GUI.clScrollBk+4*edi]
        stdcall DrawScrollerEdge, ebx, [esi+TScrollbar._width], [esi+TScrollbar._height], ecx, 0


.finish:
        inherited
        popad
        return

endp



proc DrawScrollerEdge, .pImage, .width, .height, .kind, .color
begin
        pushad

        mov     esi, [.pImage]
        mov     edi, [esi+TImage.pPixels]
        stdcall __fix_color, [.color], regEAX

        cmp     [.kind], 0
        je      .horiz

        mov     ebx, [esi+TImage.width]
        mov     edx, [.height]

        sub     edx, [.width]
        inc     edx

        imul    edx, ebx
        lea     edi, [edi+4*edx]

        xor     edx, edx

.loop:
        inc     edx
        cmp     edx, [.width]
        jge     .finish

        mov     ecx, edx
        push    edi
        rep stosd
        pop     edi

        lea     edi, [edi+4*ebx]
        jmp     .loop


.horiz:

        mov     ebx, [esi+TImage.width]
        mov     edx, [.width]

        lea     edi, [edi+4*edx-4]

        mov     edx, [.height]
        inc     edx

        lea     ebx, [4*ebx]
        std

.loopv:
        dec     edx
        jz      .finish

        mov     ecx, edx
        push    edi
        rep stosd
        pop     edi

        add     edi, ebx
        jmp     .loopv


.finish:
        cld
        popad
        return
endp


method TScrollbar.EventMouseMove
begin
        pushad

        mov     esi, [.self]
        mov     edx, [esi+TScrollbar._kind]

        cmp     [esi+TScrollbar._drag_ofs], 0
        je      .finish

        mov     eax, [.x + 4*edx]
        mov     ecx, [esi+TScrollbar._width + 4*edx]

        sub     eax, [edi+TScrollbar._drag_ofs]

        stdcall _SetSliderPos, edi, eax, ecx
        jc      .finish

        get     eax, esi, TWindow:Parent
        exec    eax, TWindow:EventScroll, edx, scTrack, [edi+TScrollbar._pos]               ;method .EventScroll, .direction, .command, .value

        exec    esi, TWindow:Refresh

.finish:
        inherited  [.x], [.y], [.kbdState]
        popad
        return
endp


method TScrollbar.EventButtonPress
begin
        pushad

        cmp     [.button], mbLeft
        jne     .finish

        mov     esi, [.self]
        mov     ebx, [esi+TScrollbar._kind]

        stdcall _SliderPixels, esi, [esi+TScrollbar._width + 4*ebx]

        mov     edi, [.x+ 4*ebx]

        sub     edi, eax
        jl      .before

        cmp     edi, edx
        jg      .after

; inside the slider - capture the mouse.

        mov     [esi+TScrollbar._drag_ofs], edi

        stdcall SetMouseCapture, esi

.finish:
        inherited [.button], [.kbdState], [.x], [.y]

        popad
        return

.before:
.after:
        jmp     .finish
endp




method TScrollbar.EventButtonRelease
begin
        pushad

        mov     esi, [.self]

        xor     eax, eax
        mov     [esi+TScrollbar._drag_ofs], eax
        stdcall SetMouseCapture, eax

        popad
        return
endp









; returns:
;   eax - position in pixels
;   edx - size in pixels


proc _SliderPixels, .pScrollbar, .length
begin
        push    ecx esi

        mov     ecx, [.pScrollbar]

; page size in pixels.
        mov     esi, [ecx+TScrollbar._max]
        mov     eax, [.length]
        add     esi, [ecx+TScrollbar._page]
        test    esi, esi
        jz      .lengthok

        imul    [ecx+TScrollbar._page]
        idiv    esi

.lengthok:
        cmp     eax, [GUI.minSliderHeight]
        cmovl   eax, [GUI.minSliderHeight]

        cmp     eax, [.length]
        cmovg   eax, [.length]

        push    eax

; position in pixels

        sub     eax, [.length]
        mov     esi, [ecx+TScrollbar._max]
        test    esi, esi
        jnz     @f
        inc     esi
@@:
        neg     eax
        mul     [ecx+TScrollbar._pos]
        div     esi

        pop     edx   ; width

        pop     esi ecx
        return
endp





proc _SetSliderPos, .pScrollbar, .x, .lengthpx
begin
        push    eax ecx edx

        mov     ecx, [.pScrollbar]
        stdcall _SliderPixels, [.pScrollbar], [.lengthpx]

        sub     [.lengthpx], edx
        jz      .zero

        mov     eax, [ecx+TScrollbar._max]
        imul    [.x]
        idiv    [.lengthpx]

        cmp     eax, 0
        jge     .ok
        mov     eax, 0
.ok:
        cmp     eax, [ecx+TScrollbar._max]
        jle     .ok2
        mov     eax, [ecx+TScrollbar._max]
.ok2:
        cmp     [ecx+TScrollbar._pos], eax
        stc
        je      @f
        clc
@@:
        mov     [ecx+TScrollbar._pos], eax
        pop     edx ecx eax
        return

.zero:
        xor     eax, eax
        jmp     .ok2
endp






method TScrollbar.EventMouseEnter
begin
        mov     eax, [.self]
        mov     [eax+TScrollbar._state], 1
        exec    eax, TWindow:Refresh

        inherited
        return
endp




method TScrollbar.EventMouseLeave
begin
        mov     eax, [.self]
        mov     [eax+TScrollbar._state], 0

        exec    eax, TWindow:Refresh

        inherited
        return
endp





endmodule



