Fresh IDE . Artifact [1d5c00faf7]
Not logged in

This repository is a mirror!

The original is located on: https://fresh.flatassembler.net/fossil/repo/fresh
If you want to follow the project, please update your remote-url

Artifact 1d5c00faf7c840c8626f9328e03c6a58b1031cd1:


; _______________________________________________________________________________________
;|                                                                                       |
;| ..::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 "TScrollable library"


struct TScrollerXY
  .pos   rd 2
  .page  rd 2
  .max   rd 2
  .step  rd 2
  .state rd 2
ends

; Constants for TScroller.state - the state of the particular scrollbar.

sbsNormal = 0   ; when the mouse is outside the scrollbar
sbsActive = 1   ; when the mouse points on the scrollbar

; Constants for TScrollable._state - the state of the window as a whole.

scsReleased = 0           ; no scrollbar is in drag state.
scsDragHorizontal = 1     ; the horizontal scrollbar is in drag state.
scsDragVertical   = 2     ; the vertical scrollbar is in drag state.



object TScrollable, TWindow

  ._scrXY  TScrollerXY

  ._drag_ofs dd ?

  ._state    dd ?

  ._imgX     dd ?
  ._imgY     dd ?

  param .PosX,  ._scrXY.pos,  .SetPos:2
  param .PageX, ._scrXY.page, .SetPage:2
  param .MaxX,  ._scrXY.max,  .SetMax:2
  param .StepX, ._scrXY.step, ._scrXY.step

  param .PosY,  ._scrXY.pos+4,  .SetPos:2
  param .PageY, ._scrXY.page+4, .SetPage:2
  param .MaxY,  ._scrXY.max+4,  .SetMax:2
  param .StepY, ._scrXY.step+4, ._scrXY.step+4

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

  method .Create, .parent
  method .Destroy

  method .__UpdateImages
  method .__DrawScrollbar, .scrollbar   ; .scrollbar == TScrollable._scrX or TScrollable._scrY
  method .__Invalidate, .scrollbar
  method .SelfPaint, .pDstImage, .xDst, .yDst, .xSrc, .ySrc, .width, .height    ; Paints itself on the caller provided TImage.

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

  method .EventButtonPress, .button, .kbdState, .x, .y
  method .EventButtonRelease, .button, .kbdState, .x, .y
  method .EventScroll, .direction, .command, .value

endobj


;_________________________________________________________________________________________


method TScrollable.Create
begin
        inherited [.parent]

        set     [.self], TScrollable:StepX, 1
        set     [.self], TScrollable:StepY, 1

        return
endp


method TScrollable.Destroy
begin
        push    esi
        mov     esi, [.self]
        stdcall DestroyImage, [esi+TScrollable._imgX]
        and     [esi+TScrollable._imgX], 0

        stdcall DestroyImage, [esi+TScrollable._imgY]
        and     [esi+TScrollable._imgY], 0

        pop     esi
        inherited
        return
endp



method TScrollable.__Invalidate ; .scrollbar
begin
        pushad
        mov     esi, [.self]

        cmp     [.scrollbar], scrollY
        je      .invalidateY

        xor     eax, eax
        mov     edx, [GUI.scrollWidth]
        mov     ebx, [esi+TScrollable._height]
        mov     ecx, [esi+TScrollable._width]
        sub     ebx, edx
        jmp     .invalidate

.invalidateY:

        xor     ebx, ebx
        mov     ecx, [GUI.scrollWidth]

        mov     eax, [esi+TScrollable._width]
        mov     edx, [esi+TScrollable._height]
        sub     eax, ecx

.invalidate:

        exec    esi, TScrollable:RectChangedXY2, eax, ebx, ecx, edx
        popad
        return
endp

;_________________________________________________________________________________________


method TScrollable.__UpdateImages
begin
        inherited
        pushad

        mov     esi, [.self]

        mov     edi, [esi+TScrollable._imgX]
        mov     ecx, [esi+TScrollable._width]
        mov     edx, [GUI.scrollWidth]

        test    edi, edi
        jz      .createx

        cmp     [edi+TImage.wrapW], ecx
        jne     .destroyx
        cmp     [edi+TImage.wrapH], edx
        je      .ximg_ok

.destroyx:

        stdcall DestroyImage, edi

.createx:
        stdcall CreateImage2, ecx, edx, FALSE
        mov     [esi+TScrollable._imgX], eax

.ximg_ok:

        mov     edi, [esi+TScrollable._imgY]
        mov     ecx, [esi+TScrollable._height]
        mov     edx, [GUI.scrollWidth]

        test    edi, edi
        jz      .createy

        cmp     [edi+TImage.wrapH], ecx
        jne     .destroyy
        cmp     [edi+TImage.wrapW], edx
        je      .yimg_ok

.destroyy:

        stdcall DestroyImage, edi

.createy:
        stdcall CreateImage2, edx, ecx, FALSE
        mov     [esi+TScrollable._imgY], eax

.yimg_ok:

        exec    esi, TScrollable:__DrawScrollbar, scrollX
        exec    esi, TScrollable:__DrawScrollbar, scrollY
        popad
        return
endp


;_________________________________________________________________________________________


method TScrollable.SetPos       ;, .param, .value
begin
        pushad

        OutputValue "SetPos: ", [.value], 10, -1

        mov     esi, [.self]
        mov     eax, [.value]

        xor     edx, edx  ;  == scrollX
        cmp     [.param], TScrollable.PosX
        je      @f
        inc     edx
@@:
        cmp     eax, [esi + TScrollable._scrXY.pos + 4*edx]
        je      .finish

        mov     [esi + TScrollable._scrXY.pos + 4*edx], eax
        exec    esi, TScrollable:__DrawScrollbar, edx
        exec    esi, TScrollable:__Invalidate, edx

        clc     ; position changed. refresh.
        popad
        return

.finish:
        stc     ; no need to refresh.
        popad
        return
endp

;_________________________________________________________________________________________


method TScrollable.SetPage         ; .param, .value
begin
        pushad

        mov     esi, [.self]
        mov     eax, [.value]

        xor     edx, edx  ; == scrollX
        cmp     [.param], TScrollable.PageX
        je      @f
        inc     edx
@@:
        cmp     eax, [esi + TScrollable._scrXY.page + 4*edx]
        je      .finish

        mov     [esi + TScrollable._scrXY.page + 4*edx], eax
        exec    esi, TScrollable:__DrawScrollbar, edx
        exec    esi, TScrollable:__Invalidate, edx

.finish:
        popad
        return
endp

;_________________________________________________________________________________________


method TScrollable.SetMax          ;, .param, .value
begin
        pushad

        mov     esi, [.self]
        mov     eax, [.value]

        xor     edx, edx
        cmp     [.param], TScrollable.MaxX
        je      @f
        inc     edx
@@:
        cmp     eax, [esi + TScrollable._scrXY.max + 4*edx]
        je      .finish

        mov     [esi + TScrollable._scrXY.max + 4*edx], eax
        exec    esi, TScrollable:__DrawScrollbar, edx
        exec    esi, TScrollable:__Invalidate, edx

.finish:
        popad
        return
endp



;_________________________________________________________________________________________


method TScrollable.SelfPaint       ;, .pDstImage, .xDst, .yDst, .xSrc, .ySrc, .width, .height
.src  RECT  ; the rectangle that need paint.
.vscr RECT  ; the vertical scroller rect.
.hscr RECT  ; the horizontal scroller rect.
.res  RECT
begin
        inherited [.pDstImage], [.xDst], [.yDst], [.xSrc], [.ySrc], [.width], [.height]
        pushad

        mov     esi, [.self]

        mov     eax, [.xSrc]
        mov     ecx, [.ySrc]
        mov     [.src.left], eax
        mov     [.src.top], ecx
        add     eax, [.width]
        add     ecx, [.height]
        mov     [.src.right], eax
        mov     [.src.bottom], ecx

        xor     eax, eax
        mov     [.vscr.top], eax
        mov     [.hscr.left], eax

        mov     ecx, [esi+TScrollable._width]
        mov     edx, [esi+TScrollable._height]

        mov     [.vscr.right], ecx
        mov     [.vscr.bottom], edx

        mov     [.hscr.right], ecx
        mov     [.hscr.bottom], edx

        sub     ecx, [GUI.scrollWidth]
        sub     edx, [GUI.scrollWidth]

        mov     [.vscr.left], ecx
        mov     [.hscr.top], edx

        lea     edx, [.src]
        lea     ebx, [.vscr]
        lea     eax, [.res]

        stdcall RectIntersect, eax, ebx, edx
        jc      .vscr_ok

        cmp     [esi + TScrollable._scrXY.max + 4], 0
        je      .vscr_ok

        mov     eax, [.res.left]
        mov     ebx, [.res.top]
        mov     ecx, eax
        mov     edx, ebx
        sub     [.res.right], eax
        sub     [.res.bottom], ebx
        sub     eax, [.vscr.left]
        sub     ebx, [.vscr.top]

        add     ecx, [.xDst]
        add     edx, [.yDst]
        sub     ecx, [.xSrc]
        sub     edx, [.ySrc]

        stdcall BlendImage, [.pDstImage], ecx, edx, [esi+TScrollable._imgY], eax, ebx, [.res.right], [.res.bottom]

.vscr_ok:
        lea     edx, [.src]
        lea     ebx, [.hscr]
        lea     eax, [.res]
        stdcall RectIntersect, eax, ebx, edx
        jc      .hscr_ok

        cmp     [esi+TScrollable._scrXY.max], 0
        je      .hscr_ok

        mov     eax, [.res.left]
        mov     ebx, [.res.top]
        mov     ecx, eax
        mov     edx, ebx
        sub     [.res.right], eax
        sub     [.res.bottom], ebx
        sub     eax, [.hscr.left]
        sub     ebx, [.hscr.top]

        add     ecx, [.xDst]
        add     edx, [.yDst]
        sub     ecx, [.xSrc]
        sub     edx, [.ySrc]

        stdcall BlendImage, [.pDstImage], ecx, edx, [esi+TScrollable._imgX], eax, ebx, [.res.right], [.res.bottom]

.hscr_ok:
        popad
        return
endp



method TScrollable.__DrawScrollbar
begin
        pushad
        mov     esi, [.self]

        cmp     [.scrollbar], scrollX
        je      .draw_x

        mov     ebx, [esi+TScrollable._imgY]
        test    ebx, ebx
        jz      .scry_ok

        mov     edi, [esi + TScrollable._scrXY.state + 4]

; Draw background Y

        mov     ecx, [ebx+TImage.wrapH]
        mov     edx, [GUI.scrollWidth]
        sub     ecx, edx
        stdcall DrawSolidRect, ebx, 0, 0, edx, ecx, [GUI.clScrollBk+4*edi]
        stdcall DrawSolidRect, ebx, 0, ecx, edx, edx, 0
        stdcall BlendTriangle, ebx, 0, ecx, edx, trtUpper or trtRight, [GUI.clScrollBk+4*edi]

; Draw slider Y
        lea     eax, [esi + TScrollable._scrXY]
        stdcall _SliderPixels2, eax, scrollY, ecx

        cmp     eax, ecx
        cmovg   eax, ecx

        mov     ecx, [esi + TScrollable._scrXY.pos + 4]
        cmp     ecx, [esi + TScrollable._scrXY.max + 4]
        cmovg   ecx, [GUI.clScrollSliderOvf+4*edi]
        cmovle  ecx, [GUI.clScrollSlider+4*edi]

        stdcall BlendSolidRect, ebx, 0, eax, [GUI.scrollWidth], edx, ecx
        add     eax, edx
        stdcall BlendTriangle,  ebx, 0, eax, [GUI.scrollWidth], trtUpper or trtRight, ecx

.scry_ok:
        popad
        return


.draw_x:
        mov     ebx, [esi+TScrollable._imgX]
        test    ebx, ebx
        jz      .scrx_ok

        mov     edi, [esi+TScrollable._scrXY.state]

; Draw background X

        mov     ecx, [ebx+TImage.wrapW]
        mov     edx, [GUI.scrollWidth]
        sub     ecx, edx
        stdcall DrawSolidRect, ebx, 0, 0, ecx, edx, [GUI.clScrollBk+4*edi]
        stdcall DrawSolidRect, ebx, ecx, 0, edx, edx, 0
        stdcall BlendTriangle, ebx, ecx, 0, edx, trtLower or trtLeft, [GUI.clScrollBk+4*edi]

; Draw slider X

        lea     eax, [esi+TScrollable._scrXY]
        stdcall _SliderPixels2, eax, scrollX, ecx

        cmp     eax, ecx
        cmovg   eax, ecx

        mov     ecx, [esi+TScrollable._scrXY.pos]
        cmp     ecx, [esi+TScrollable._scrXY.max]
        cmovg   ecx, [GUI.clScrollSliderOvf+4*edi]
        cmovle  ecx, [GUI.clScrollSlider+4*edi]

        stdcall BlendSolidRect, ebx, eax, 0, edx, [GUI.scrollWidth], ecx
        add     eax, edx
        stdcall BlendTriangle,  ebx, eax, 0, [GUI.scrollWidth], trtLower or trtLeft, ecx

.scrx_ok:
        popad
        return
endp



; returns:
;   EAX:
;       -1 - the coordinates are outside the scrollbars
;        0 - the coordinates are in the horizontal scrollbar
;        1 - the coordinates are in the vertical scrollbar

proc __FindScroller, .scrollable, .x, .y
begin
        push    esi ecx edx

        mov     esi, [.scrollable]

        xor     eax, eax
        dec     eax

        mov     ecx, [esi+TWindow._width]
        mov     edx, [esi+TWindow._height]
        sub     ecx, [.x]
        sub     edx, [.y]

        cmp     ecx, [GUI.scrollWidth]
        jl      .y_scroller

        cmp     edx, [GUI.scrollWidth]
        jge     .finish

        cmp     ecx, edx
        jl      .yes_y_scroller

.yes_x_scroller:

        inc     eax
        jmp     .finish

.y_scroller:

        cmp     ecx, edx
        jge     .yes_x_scroller

.yes_y_scroller:

        inc     eax
        inc     eax

.finish:
        pop     edx ecx esi
        return
endp




method TScrollable.EventMouseLeave
begin
        push    esi ecx edx

        mov     esi, [.self]

        xor     ecx, ecx
        xor     edx, edx
        xchg    ecx, [esi+TScrollable._scrXY.state]
        xchg    edx, [esi+TScrollable._scrXY.state + 4]
        or      ecx, edx
        jz      .finish

        xor     edx, edx ; == scrollX
        exec    esi, TScrollable:__DrawScrollbar, edx
        exec    esi, TScrollable:__Invalidate, edx
        inc     edx      ; == scrollY
        exec    esi, TScrollable:__DrawScrollbar, edx
        exec    esi, TScrollable:__Invalidate, edx

.finish:
        pop     edx ecx esi
        return
endp



method TScrollable.EventMouseMove
.dummy  dd ?
.stateH dd ?
.stateV dd ?
begin
        pushad

        mov     esi, [.self]
        mov     ebx, [esi + TScrollable._state]

        test    ebx, ebx
        jnz     .process_drag

        xor     ecx, ecx
        mov     [.stateH], ecx
        mov     [.stateV], ecx

        stdcall __FindScroller, esi, [.x], [.y]
        inc     [.stateH+4*eax]         ; notice the .dummy variable for eax = -1

        mov     ecx, [esi+TWindow._cursor]
        inc     eax
        jz      @f
        mov     ecx, mcArrow
@@:
        get     edx, esi, TWindow:OSWindow
        stdcall GetStockCursor, ecx
        stdcall SetMouseCursor, [edx+TWindow.handle], eax

        xor     eax, eax
        mov     ebx, [.stateH]
        xchg    ebx, [esi+TScrollable._scrXY.state]
        xor     ebx, [esi+TScrollable._scrXY.state]
        jz      .statex_ok

        exec    esi, TScrollable:__DrawScrollbar, scrollX
        exec    esi, TScrollable:__Invalidate, scrollX

.statex_ok:
        mov     ebx, [.stateV]
        xchg    ebx, [esi+TScrollable._scrXY.state+4]
        xor     ebx, [esi+TScrollable._scrXY.state+4]
        or      eax, ebx
        jz      .statey_ok   ; if the state has not be changed.

        exec    esi, TScrollable:__DrawScrollbar, scrollY
        exec    esi, TScrollable:__Invalidate, scrollY

.statey_ok:
        inherited  [.x], [.y], [.kbdState]
        clc
        popad
        return


.process_drag:

        dec     ebx

        mov     eax, [.x + 4*ebx]
        mov     ecx, [esi+TScrollable._width + 4*ebx]

        sub     eax, [esi+TScrollable._drag_ofs]
        lea     edx, [esi+TScrollable._scrXY]

        stdcall _ComputeSliderPos, edx, ebx, eax, ecx
        jc      .finish

        exec    esi, TScrollable:EventScroll, ebx, scTrack, eax

.finish:
        stc
        popad
        return
endp



; computes the position of the slider from screen pixel coordinates.
proc _ComputeSliderPos, .pScroller, .direction, .x, .lengthpx
begin
        push    ecx edx

        stdcall _SliderPixels2, [.pScroller], [.direction], [.lengthpx] ; the length of the slider.

        mov     ecx, [.direction]
        shl     ecx, 2
        add     ecx, [.pScroller]

        sub     [.lengthpx], edx
        jz      .zero

        mov     eax, [ecx + TScrollerXY.max]
        imul    [.x]
        idiv    [.lengthpx]

        xor     edx, edx

        cmp     eax, edx
        cmovl   eax, edx

        mov     edx, [ecx + TScrollerXY.max]
        cmp     eax, edx
        cmovg   eax, edx
        clc

.ok:
        pop     edx ecx
        return

.zero:
        stc
        xor     eax, eax
        jmp     .ok
endp




method TScrollable.EventButtonPress
begin
        pushad

        cmp     [.button], mbLeft
        jne     .not_processed

        mov     esi, [.self]

        stdcall __FindScroller, esi, [.x], [.y]
        test    eax, eax
        js      .not_processed

        mov     ebx, eax

        lea     eax, [esi + TScrollable._scrXY]
        stdcall _SliderPixels2, eax, ebx, [esi+TScrollable._width + 4*ebx]
        mov     edi, [.x + 4*ebx]

        mov     ecx, [esi + TScrollable._width + 4*ebx]   ; if pos is > max
        sub     ecx, edx
        cmp     eax, ecx
        cmovg   eax, ecx

        sub     edi, eax
        jl      .before

        cmp     edi, edx
        jg      .after

; inside the slider - capture the mouse.

        mov     [esi + TScrollable._drag_ofs], edi
        inc     ebx
        mov     [esi + TScrollable._state], ebx

        stdcall SetMouseCapture, esi

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

        stc
        popad
        return

.before:
.after:
        jmp     .finish


.not_processed:
        clc
        popad
        return
endp




method TScrollable.EventButtonRelease
begin
        pushad

        mov     esi, [.self]
        xor     eax, eax
        cmp     [esi+TScrollable._state], eax
        je      .finish

        mov     [esi+TScrollable._drag_ofs], eax
        mov     [esi+TScrollable._state], eax
        stdcall SetMouseCapture, eax

        exec    esi, TScrollable:EventMouseMove, [.x], [.y], [.kbdState]

.finish:
        popad
        return
endp



method TScrollable.EventScroll
begin
        pushad

        mov     esi, [.self]

        cmp     [.direction], scrollX
        je      .horiz_scroll

        cmp     [.command], scWheelUp
        je      .scrollupy

        cmp     [.command], scWheelDn
        je      .scrolldny

        cmp     [.command], scTrack
        je      .track

        clc
        popad
        return


.finish:
        popad
        return

.track:
        set     esi, TScrollable:PosY, [.value]
        jmp     .finish


.scrollupy:
        get     ecx, esi, TScrollable:StepY
        get     eax, esi, TScrollable:PosY

        sub     eax, ecx
        jns     @f
        xor     eax, eax
@@:
        set     esi, TScrollable:PosY, eax
        jmp     .finish


.scrolldny:
        get     edx, esi, TScrollable:MaxY
        get     ecx, esi, TScrollable:StepY
        get     eax, esi, TScrollable:PosY

        add     eax, ecx
        cmp     eax, edx
        cmovg   eax, edx

        set     [.self], TScrollable:PosY, eax
        jmp     .finish


.horiz_scroll:
        cmp     [.command], scWheelUp
        je      .scrollupx

        cmp     [.command], scWheelDn
        je      .scrolldnx

        cmp     [.command], scTrack
        jne     .finish

        set     esi, TScrollable:PosX, [.value]
        jmp     .finish


.scrollupx:
        get     ecx, esi, TScrollable:StepX
        get     eax, esi, TScrollable:PosX

        sub     eax, ecx
        jns     @f
        xor     eax, eax
@@:
        set     esi, TScrollable:PosX, eax
        jmp     .finish

.scrolldnx:
        get     edx, esi, TScrollable:MaxX
        get     ecx, esi, TScrollable:StepX
        get     eax, esi, TScrollable:PosX

        add     eax, ecx
        cmp     eax, edx
        cmovg   eax, edx

        set     [.self], TScrollable:PosX, eax
        jmp     .finish
endp






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


proc _SliderPixels2, .pScroller, .direction, .length
begin
        push    ecx esi

        mov     ecx, [.pScroller]
        mov     eax, [.direction]
        lea     ecx, [ecx+4*eax]

; page size in pixels.
        mov     esi, [ecx + TScrollerXY.max]
        mov     eax, [.length]

        add     esi, [ecx + TScrollerXY.page]
        test    esi, esi
        jz      .lengthok

        imul    [ecx + TScrollerXY.page]
        idiv    esi

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

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

        push    eax  ; width

; position in pixels

        sub     eax, [.length]
        mov     esi, [ecx + TScrollerXY.max]
        test    esi, esi
        jnz     @f
        inc     esi
@@:
        neg     eax
        mul     [ecx + TScrollerXY.pos]
        div     esi

        pop     edx   ; width

        pop     esi ecx
        return
endp









endmodule