proc AlignChildren, .hwnd
.InternalData TInternalAlign
.bounds       TBounds
.class        rw 64
begin
        push    esi edi

        lea     esi, [.InternalData.client]
        invoke  GetClientRect, [.hwnd], esi

        lea     esi, [.class]
        invoke  GetClassNameW, [.hwnd], esi, 64
        mov     ecx, eax

        mov     edi, cTabClassName      ; is it TabControl?
        repe cmpsw
        lea     esi, [.InternalData]
        jne     .tab_ok

        invoke  SendMessageW, [.hwnd], TCM_ADJUSTRECT, FALSE, esi

.tab_ok:
        and     [.InternalData.hClientWindow], 0

        invoke  BeginDeferWindowPos, 10
        mov     [.InternalData.hDefer], eax

        invoke  GetWindow, [.hwnd], GW_CHILD

.childrenloop:
        test    eax, eax
        jz      .endchildren

        push    GW_HWNDNEXT
        push    eax
        stdcall DoAlignOne, eax
        invoke  GetWindow ; from the stack
        jmp     .childrenloop

.endchildren:
        cmp     [.InternalData.hClientWindow], 0
        je      .enddefer

        lea     eax, [.bounds]
        stdcall AlignWindow, [esi+TInternalAlign.hClientWindow], esi, eax, waClient
        test    eax, eax
        jz      .enddefer

        invoke  DeferWindowPos, [.InternalData.hDefer],         \
                                [.InternalData.hClientWindow],  \
                                eax,                            \
                                [.bounds.x], [.bounds.y],       \
                                [.bounds.width], [.bounds.height], \
                                SWP_NOZORDER or SWP_NOCOPYBITS or SWP_NOACTIVATE
.enddefer:
        invoke  EndDeferWindowPos, [.InternalData.hDefer]
        pop     edi esi
        return
endp



proc DoAlignOne, .hwnd
.bounds TBounds
begin
        push    ebx

        invoke  GetPropW, [.hwnd], [propAlign]
        test    eax, eax
        jz      .exit
        mov     ebx, eax

        invoke  GetWindowLongW, [.hwnd], GWL_STYLE
        test    eax,WS_VISIBLE
        jz      .exit

        cmp     ebx, waClient
        jne     .doalign

; only one window with waClient may exists.
        cmp     [esi+TInternalAlign.hClientWindow], 0
        jne     .exit

        mov     eax, [.hwnd]
        mov     [esi+TInternalAlign.hClientWindow], eax
        jmp     .exit


.doalign:
        lea     eax, [.bounds]
        stdcall AlignWindow, [.hwnd], esi, eax, ebx
        test    eax, eax
        jz      .exit

        invoke  DeferWindowPos, [esi+TInternalAlign.hDefer],       \
                                [.hwnd],                           \
                                eax,                               \
                                [.bounds.x], [.bounds.y],          \
                                [.bounds.width], [.bounds.height], \
                                SWP_NOZORDER or SWP_NOCOPYBITS

.exit:
        mov     eax, 1
        pop     ebx
        return
endp




;************************************************************
;  Alignes some window in the bounds of ptrClientRect
;  rectangle. Excludes the result window from the
;  rectangle.
;  Returns the result x,y,w and h of the window in
;  ptrWinBounds
;
;  Returns: TRUE if the window is resized and FALSE if not.
;************************************************************
proc AlignWindow, .hwnd, .ptrClientRect, .ptrWinBounds, .winalign

.winrect RECT
.oldrect RECT

begin

        push    esi edi ecx ebx edx

        invoke  GetWindowLongW, [.hwnd], GWL_STYLE
        test    eax,WS_VISIBLE
        jz      .exit

        lea     esi,[.oldrect]
        invoke  GetWindowRect, [.hwnd], esi
        invoke  GetParent, [.hwnd]
        push    esi eax
        add     esi, 8
        invoke  ScreenToClient, eax, esi
        invoke  ScreenToClient ; from the stack.

        mov     esi, [.ptrClientRect]             ; Parent client rect pointer
        lea     edi, [.winrect]
        mov     ecx, 4
        rep movsd       ; copy client rect to window rect.

        mov     edx,[.oldrect.right]
        mov     ecx,[.oldrect.bottom]
        sub     edx,[.oldrect.left]             ; width of window
        sub     ecx,[.oldrect.top]              ; height of window
        mov     esi, [.ptrClientRect]             ; Parent client rect pointer

        mov     ebx,[.winalign]
        cmp     ebx, waClient
        jg      .exit
        cmp     ebx, waNone
        jle     .exit

        mov     eax, [.tableAlignProc+4*ebx-4]
        call    eax  ; make adjustment of the size and client rect.

; is rectangle changed?
        mov     eax,[.oldrect.top]
        mov     ebx,[.oldrect.left]
        mov     ecx,[.oldrect.right]
        mov     edx,[.oldrect.bottom]

        sub     eax,[.winrect.top]
        sub     ebx,[.winrect.left]
        sub     ecx,[.winrect.right]
        sub     edx,[.winrect.bottom]

        or      eax,ebx
        or      ecx,edx
        or      eax,ecx                 ; eax is NULL an ZF = 1 if .winrect = .oldrect
        jz      .end

        mov     eax,[.winrect.right]
        mov     ebx,[.winrect.bottom]
        sub     eax,[.winrect.left]
        jns     @f
        xor     eax,eax
@@:
        sub     ebx,[.winrect.top]
        jns     @f
        xor     ebx,ebx
@@:
        mov     esi,[.ptrWinBounds]

        mov     [esi+TBounds.width],eax
        mov     [esi+TBounds.height],ebx

        push    [.winrect.left]
        push    [.winrect.top]
        pop     [esi+TBounds.y]
        pop     [esi+TBounds.x]

        xor     eax,eax
        dec     eax
        jmp     .end

.exit:
        xor     eax, eax
.end:
        pop     edx ebx ecx edi esi
        return


.tableAlignProc dd .left, .right, .top, .bottom, .client

; align left
.left:
        mov     eax, [.winrect.left]
        add     eax, edx
        mov     [.winrect.right], eax
        add     [esi+RECT.left],edx            ; move the client rect
        ret

; align right
.right:
        mov     eax, [.winrect.right]
        sub     eax ,edx
        mov     [.winrect.left],eax
        sub     [esi+RECT.right],edx            ; move the client rect
        ret

; align top
.top:
        mov     eax, [.winrect.top]
        add     eax, ecx
        mov     [.winrect.bottom],eax
        add     [esi+RECT.top],ecx            ; move the client rect
        ret

; align bottom
.bottom:
        mov     eax, [.winrect.bottom]
        sub     eax, ecx
        mov     [.winrect.top], eax
        sub     [esi+RECT.bottom],ecx            ; move the client rect
        ret

; align client
.client:
        xor     eax,eax
        mov     [esi+RECT.left],eax
        mov     [esi+RECT.right],eax
        mov     [esi+RECT.top],eax
        mov     [esi+RECT.bottom],eax          ; make client rect missing
        ret
endp


proc AlignSiblings, .hwnd
begin
        invoke  GetParent, [.hwnd]
        test    eax, eax
        jz      .exit
        stdcall AlignChildren, eax
.exit:
        return
endp