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