; _______________________________________________________________________________________
;| |
;| ..::FreshLib::.. Free, open source. Licensed under "BSD 2-clause" license." |
;|_______________________________________________________________________________________|
;
; Description: Objects template engine
;
; Target OS: Any
;
; Dependencies: objects.asm
;
; Notes:
;_________________________________________________________________________________________
module "SplitGrid"
stOriginBR = $08 ; the origin of the cell splitter is on the right (or bottom)
; edge of the cell.
stHoriz = $00 ; the cell is splitted on left and right parts.
stVert = $04 ; the cell is splitted on up and down parts.
stNone = $80 ; the cell is not splitted.
stRelative = $4000 ; the pos field is a part of a whole (in 1/32768 units)
stJustGap = $8000 ; the rectangle is splitted, but not resizeable.
struct TSplitRect
.rect RECT ; the rectangle of the area.
.spRect RECT ; rectangle of the splitter.
.pWindow dd ? ; pointer to TWindow descendent, bound to the grid cell.
.pos dd ? ; in pixels or as part of the whole.
.min dd ? ; minimal size
.max dd ? ; maximal size
.type dd ? ; one or more of stXXXXX flags defined above.
.spWidth dd ? ; width of the spliter
.id dd ?
ends
struct TSplitTemplate
.type dw ? ; stXXXXXXXXX flags
.width dw ? ; width of the splitter
.pos dd ? ; current position
.min dd ? ; min
.max dd ? ; max
ends
struct TCellTemplate
.type dw ?
.id dw ?
ends
macro SplitStart name {
local ..expected, ..id
..expected = 1
..id = 0
cell@expected equ ..expected
cell@id equ ..id
cell@name equ name
label name byte
macro Split type, width, pos, min, max \{
dw type, width
dd pos, min, max
cell@id = cell@id + 1
cell@expected = cell@expected + 1
\}
macro Cell name \{
.\#name = cell@id
dw stNone, cell@id
cell@id = cell@id + 1
cell@expected = cell@expected - 1
\}
}
macro SplitEnd {
match name, cell@name \{ cell@namestr equ `name \}
if cell@expected<>0
disp 1, 'WARNING! "', cell@namestr, '" split template is not consistent! Automatically added ', <cell@expected, 10>, " empty cells. FIXIT!", 13
repeat cell@expected
dw stNone, 0
end repeat
end if
match name, cell@name \{ sizeof.\#name = $ - name \}
purge Cell, Split
restore cell@expected, cell@id, cell@name
}
struc SplitTemplate [name, type, width, pos, min, max] {
common
.:
local ..expected, ..index
..expected = 1
..index = 0
forward
if ~name eq NONE
name = ..index
end if
dw type
dw width
dd pos
dd min
dd max
if (type <> stNone)
..expected = ..expected + 1
else
..expected = ..expected - 1
end if
..index = ..index + 1
common
repeat ..expected
dw stNone, 0
dd 0, 0, 0
end repeat
if ..expected <> 0
disp 1, 'WARNING! "', `., '" split template is not consistent! Automatically added ', <..expected, 10>, " empty cells. FIXIT!", 13
end if
}
proc RealignGrid, .ptrSplitter, .ptrRect
.rect RECT
begin
pushad
mov edi, [.ptrSplitter]
mov esi, [.ptrRect]
call _DoRealign
popad
return
endp
; edi is pointer to the current TSplitRect
; esi is pointer to the rect that have to be assigned to the current TSplitRect
proc _DoRealign
.rect1 RECT
.rect2 RECT
begin
; copy the rect to the target rectangles.
mov eax, [esi+RECT.left]
mov ecx, [esi+RECT.top]
mov [edi+TSplitRect.rect.left], eax
mov [edi+TSplitRect.rect.top], ecx
mov [edi+TSplitRect.spRect.left], eax
mov [edi+TSplitRect.spRect.top], ecx
mov [.rect1.left], eax
mov [.rect1.top], ecx
mov [.rect2.left], eax
mov [.rect2.top], ecx
mov eax, [esi+RECT.right]
mov ecx, [esi+RECT.bottom]
mov [edi+TSplitRect.rect.right], eax
mov [edi+TSplitRect.rect.bottom], ecx
mov [edi+TSplitRect.spRect.right], eax
mov [edi+TSplitRect.spRect.bottom], ecx
mov [.rect1.right], eax
mov [.rect1.bottom], ecx
mov [.rect2.right], eax
mov [.rect2.bottom], ecx
mov esi, edi ; current TSplitRect
add edi, sizeof.TSplitRect ; goto next one
mov ecx, [esi+TSplitRect.type]
test ecx, stNone
jnz .endsplit
; There is split, so compute it.
and ecx, stVert
mov ebx, [esi+ecx+TSplitRect.rect.right]
sub ebx, [esi+ecx+TSplitRect.rect.left] ; size of rect (x or y depending on type)
mov edx, [esi+TSplitRect.spWidth]
sub ebx, edx
mov eax, [esi+TSplitRect.pos]
cmp eax, [esi+TSplitRect.min]
cmovl eax, [esi+TSplitRect.min]
cmp eax, [esi+TSplitRect.max]
cmovg eax, [esi+TSplitRect.max]
mov [esi+TSplitRect.pos],eax
mov ecx, [esi+TSplitRect.type]
and ecx, $ff
test [esi+TSplitRect.type], stRelative
jz .posready
imul eax, ebx
sar eax, 15 ; div $8000
.posready:
test ecx, stOriginBR
jz .readyofs ; it is Left or Top
neg edx
neg eax
.readyofs:
add eax, [.rect1.left+ecx]
mov [.rect1.right+ecx], eax
mov [esi+ecx+TSplitRect.spRect], eax
add ecx, 8 ; right or bottom
and ecx, $0f
add eax, edx
mov [.rect1.right+ecx], eax
mov [esi+ecx+TSplitRect.spRect], eax
push esi
lea esi, [.rect1]
call _DoRealign
lea esi, [.rect2]
call _DoRealign
pop esi
jmp .endresize
.endsplit:
mov ebx, [esi+TSplitRect.pWindow]
test ebx, ebx
jz .endresize
mov eax, [esi+TSplitRect.rect.left]
mov ecx, [esi+TSplitRect.rect.top]
exec ebx, TWindow:Move, eax, ecx
mov eax, [esi+TSplitRect.rect.right]
mov ecx, [esi+TSplitRect.rect.bottom]
sub eax, [esi+TSplitRect.rect.left]
sub ecx, [esi+TSplitRect.rect.top]
xor edx, edx
test eax, eax
cmovs eax, edx
test ecx, ecx
cmovs ecx, edx
exec ebx, TWindow:Resize, eax, ecx
.endresize:
return
endp
proc DrawSplitters, .pImage, .ptrSplitters
begin
pushad
mov esi, [.ptrSplitters]
mov edi, [.pImage]
call _DoDrawSplitters
popad
return
endp
;esi - pointer to TSplitRect
; edi - TImage
proc _DoDrawSplitters
begin
mov ebx, esi
add esi, sizeof.TSplitRect
test [ebx+TSplitRect.type], stNone
jnz .exit
test [ebx+TSplitRect.type], stJustGap
jnz .next
lea eax, [ebx+TSplitRect.spRect]
stdcall [DrawSplitter], edi, eax, [ebx+TSplitRect.type]
.next:
call _DoDrawSplitters ; first
call _DoDrawSplitters ; second
.exit:
return
endp
; Returns:
; CF=1; the splitter has been found. EAX=pointer to TSplitRect structure.
; CF=0; the splitter has not been found. EAX not changed.
proc FindSplitter, .ptrSplitters, .ptrPoint
begin
pushad
mov esi, [.ptrSplitters]
mov edi, [.ptrPoint]
call _DoFindSplitter
jnc .exit
mov [esp+4*regEAX], ebx
.exit:
popad
return
endp
proc _DoFindSplitter
begin
mov ebx, esi
add esi, sizeof.TSplitRect
test [ebx+TSplitRect.type], stNone
jnz .exit
lea eax, [ebx+TSplitRect.spRect]
stdcall PointInRect, eax, [edi+POINT.x], [edi+POINT.y]
jnc .next
return
.next:
call _DoFindSplitter ; first
jc .exit
call _DoFindSplitter ; second
.exit:
return
endp
proc FindSplitterCell, .ptrSplitters, .ptrPoint
begin
mov esi, [.ptrSplitters]
mov ecx, 1 ; one splitter expected.
.loop:
add ecx, 2
test [esi+TSplitRect.type], stNone
jz .next
sub ecx, 2
lea eax, [esi+TSplitRect.rect]
stdcall PointInRect, esi, [.ptrPoint]
jc .found
.next:
lea esi, [esi+sizeof.TSplitRect]
dec ecx
jnz .loop
; here CF=0
popad
return
.found:
; here CF=1
mov [esp+regEAX*4], esi
popad
return
endp
proc ReadSplitGridTemplate, .ptrTemplate
begin
pushad
mov edx, [.ptrTemplate]
test edx, edx
jz .finish
mov esi, edx
stdcall CreateArray, sizeof.TSplitRect
mov edx, eax
mov ecx, 1
.read_loop:
stdcall AddArrayItems, edx, 1
push eax ecx
mov edi, eax
mov ecx, sizeof.TSplitRect/4
xor eax, eax
rep stosd
pop ecx edi
xor eax, eax
lodsw ; the stXXX values.
mov [edi+TSplitRect.type], eax
test eax, stNone
jnz .empty_cell
lodsw ; the width
mov [edi+TSplitRect.spWidth], eax
lodsd
mov [edi+TSplitRect.pos], eax
lodsd
mov [edi+TSplitRect.min], eax
lodsd
mov [edi+TSplitRect.max], eax
inc ecx
jmp .read_loop
.empty_cell:
lodsw
mov [edi+TSplitRect.id], eax
dec ecx
jnz .read_loop
.finish:
mov [esp+regEAX*4], edx
popad
return
endp
endmodule