initialize RegisterSizerClass
.wc WNDCLASS
begin
        xor     ebx, ebx

        mov     [.wc.hIcon],ebx
        mov     [.wc.hCursor],ebx
        mov     [.wc.style], CS_PARENTDC
        mov     [.wc.lpfnWndProc], SizerWinProc
        mov     [.wc.cbClsExtra],ebx
        mov     [.wc.cbWndExtra], 16
        mov     eax, [hInstance]
        mov     [.wc.hInstance],eax
        mov     [.wc.hbrBackground], ebx
        mov     [.wc.lpszMenuName], ebx
        mov     [.wc.lpszClassName], cSizerClassName

        lea     eax, [.wc]
        invoke  RegisterClassW, eax
        return
endp



iglobal
cSizerClassName du 'SzBx', 0

  SizerGripSize dd 8
  clSizerSize   dd $d8ffd8
  clSizerMove   dd $a0c0ff
endg


proc SizerWinProc, .hwnd, .wmsg, .wparam, .lparam
  .cursorpos POINT
begin
        push    esi edi ebx

        invoke  GetWindowLongW, [.hwnd], 0
        mov     edi, eax

        dispatch [.wmsg]

.ondefault:
        invoke  DefWindowProcW, [.hwnd], [.wmsg], [.wparam], [.lparam]
        pop     ebx edi esi
        return

;-----------------------------------------------------------------------
oncase WM_NCHITTEST
        stdcall GetCurrentTool
        test    eax, eax
        jnz     .transp

        movsx   ecx, word [.lparam]
        movsx   edx, word [.lparam+2]
        mov     [.cursorpos.x], ecx
        mov     [.cursorpos.y], edx
        lea     ecx, [.cursorpos]
        invoke  ScreenToClient, [.hwnd], ecx
        invoke  PtInRegion, [edi+TSizer.region], [.cursorpos.x], [.cursorpos.y]
        test    eax, eax
        jnz     .ondefault

.transp:
        mov     eax, HTTRANSPARENT
        pop     ebx edi esi
        return

;-----------------------------------------------------------------------
oncase WM_MOUSEACTIVATE
        invoke  SetFocus, [.hwnd]
        mov     eax, MA_ACTIVATE
        pop     ebx edi esi
        return

;-----------------------------------------------------------------------
oncase WM_GETDLGCODE

        mov     eax, DLGC_WANTALLKEYS
        clc
        return


;-----------------------------------------------------------------
oncase WM_KEYDOWN

        cmp     [.wparam], VK_ESCAPE
        jne     .ondefault

        mov     eax, [edi+TSizer.selected]
        cmp     [eax+TArray.count], 0
        je      .ondefault

        mov     esi, [eax+TArray.array]

        mov     edi, [esi+TWinTemplateDT.parent]
        test    edi, edi
        jz      .endselparent

        mov     esi, [edi+TWinTemplateDT.parent]
        test    esi, esi
        jz      .onlyprop

        invoke  SendMessageW, [.hwnd], SZM_SELECTCONTROL, edi, 0

.endselparent:
        xor     eax, eax
        pop     ebx edi esi
        return

.onlyprop:
        invoke  SendMessageW, [.hwnd], SZM_UNSELECTALL, 0, 0
        invoke  SendMessageW, [hPropEditor], PEM_SETCONTROL, edi, 0
        xor     eax, eax
        pop     ebx edi esi
        return

;-----------------------------------------------------------------------
oncase WM_CREATE

        stdcall GetMem, sizeof.TSizer
        mov     edi, eax

        invoke  SetWindowLongW, [.hwnd], 0, edi

        stdcall CreateArray, 4
        mov     [edi+TSizer.selected], eax

        xor     eax, eax
        pop     ebx edi esi
        return

;-----------------------------------------------------------------------
oncase WM_DESTROY
        stdcall FreeMem, [edi+TSizer.selected]
        cmp     [edi+TSizer.region], 0
        je      @f
        invoke  DeleteObject, [edi+TSizer.region]
@@:
        stdcall FreeMem, edi
        xor     eax, eax
        pop     ebx edi esi
        return

;-----------------------------------------------------------------------
oncase SZM_UPDATESIZE
        stdcall UpdateSizerSize, [.hwnd], edi
        pop     ebx edi esi
        return

;-----------------------------------------------------------------------
oncase SZM_UNSELECTALL
        stdcall FreeMem, [edi+TSizer.selected]
        stdcall CreateArray, 4
        mov     [edi+TSizer.selected], eax

        stdcall UpdateSizerSize, [.hwnd], edi
        pop     ebx edi esi
        return

;-----------------------------------------------------------------------
oncase SZM_SELECTCONTROL     ; .wparam - pointer to TWinTemplateDT

        mov     eax, [.wparam]
        mov     esi, [eax+TWinTemplateDT.parent]
        test    esi, esi
        jz      .topropedit     ; the top-level window can't be selected.

        invoke  GetParent, [.hwnd]
        cmp     [esi+TWinTemplateDT.hwnd], eax
        je      .parentOK

; Move the sizer to the new parent...
; First clear the selection.
        stdcall  FreeMem, [edi+TSizer.selected]
        stdcall  CreateArray, 4
        mov      [edi+TSizer.selected], eax

; Second move the sizer to the new parent.
        invoke    SetParent, [.hwnd], [esi+TWinTemplateDT.hwnd]
        mov       esi, [.wparam]
        jmp       .selectit

.parentOK:
        cmp     [.lparam], sfDontClearOld
        je      .clearok

; Clear the old selection...
        stdcall  FreeMem, [edi+TSizer.selected]
        stdcall  CreateArray, 4
        mov      [edi+TSizer.selected], eax

.clearok:
        mov     esi, [.wparam]
        stdcall ListIndexOf, [edi+TSizer.selected], esi
        jnc     .topropedit

; so, add it to selection list...
.selectit:
        stdcall AddArrayItems, [edi+TSizer.selected], 1
        mov     [edi+TSizer.selected], edx
        mov     [eax], esi

.topropedit:
        invoke  SendMessageW, [hPropEditor], PEM_SETCONTROL, esi, 0

.endselect:
        stdcall UpdateSizerSize, [.hwnd], edi
        invoke  SetFocus, [.hwnd]
        pop     ebx edi esi
        return


;-----------------------------------------------------------------------
oncase SZM_UNSELECTCONTROL

        stdcall ListIndexOf, [edi+TSizer.selected], [.wparam]
        jc      .endselect

        stdcall DeleteArrayItems, [edi+TSizer.selected], eax, 1
        mov     [edi+TSizer.selected], edx
        jmp     .endselect

;-----------------------------------------------------------------------
oncase WM_SETCURSOR
        mov     ecx, IDC_ARROW
        mov     eax, [edi+TSizer.selected]
        cmp     [eax+TArray.count], 1
        jg      .setit

        stdcall ComputeDragKind, [.hwnd], [SizerGripSize]

        movsx   ecx, ah
        shl     ecx, 2
        movsx   eax, al
        add     ecx, eax

        mov     ecx, [SizerCursors+4*ecx]

.setit:
        invoke  LoadCursorW, NULL, ecx
        invoke  SetCursor,eax
        pop     ebx edi esi
        return

;-----------------------------------------------------------------------
oncase WM_LBUTTONDOWN
  locals
    .parentrect RECT
  endl
        test    [.wparam], MK_CONTROL
        jnz     .unselect             ; unselect control under the cursor

;        test    [.wparam], MK_SHIFT
;        je      .cancelsend          ; clears all selections and resend the message to the control under the mouse.

        mov     [edi+TSizer.moveX], 3
        mov     [edi+TSizer.moveY], 3

        mov     eax, [edi+TSizer.selected]
        cmp     [eax+TArray.count], 1
        jg     .capturethemouse

; single selected - resize enabled.
        stdcall ComputeDragKind, [.hwnd], [SizerGripSize]
        movsx   ecx, ah  ; X
        movsx   edx, al  ; Y

        shl     ecx, 2
        shl     edx, 2

        movsx   ebx, al
        add     ecx, ebx
        movsx   ebx, ah
        add     edx, ebx

        movsx   ecx, [SizerXYInc+ecx]
        mov     [edi+TSizer.moveX], ecx

        movsx   edx, [SizerXYInc+edx]
        mov     [edi+TSizer.moveY], edx

.capturethemouse:
        lea     eax, [.cursorpos]
        invoke  GetCursorPos, eax

        cmp     [edi+TSizer.moveY], 3
        jne     .cursorok

        invoke  LoadCursorW, NULL, IDC_SIZEALL
        invoke  SetCursor, eax

.cursorok:
        invoke  DragDetect, [.hwnd], [.cursorpos.x], [.cursorpos.y]
        test    eax, eax
        jz      .captureOK

; store mouse coordinates in drag point.
        movsx   eax, word [.lparam]
        movsx   ecx, word [.lparam+2]
        mov     [edi+TSizer.dragXY.x], eax
        mov     [edi+TSizer.dragXY.y], ecx

        invoke  SetCapture, [.hwnd]
        invoke  GetParent, [.hwnd]
        mov     ebx, eax

        lea     esi, [.parentrect]
        invoke  GetClientRect, ebx, esi
        invoke  ClientToScreen, ebx, esi
        lea     eax, [.parentrect.right]
        invoke  ClientToScreen, ebx, eax

        invoke  ClipCursor, esi

.captureOK:
        xor     eax, eax
        pop     ebx edi esi
        return

.unselect:
        lea     ebx, [.cursorpos]
        invoke  GetCursorPos, ebx
        invoke  GetParent, [.hwnd]
        invoke  ScreenToClient, eax, ebx

        mov     esi, [edi+TSizer.selected]
        mov     ebx, [esi+TArray.count]

.unselectloop:
  locals
    .winrect RECT
  endl
        dec     ebx
        js      .endunselect

        mov     eax, [esi+4*ebx+TArray.array]
        movsx   ecx, [eax+TWinTemplateDT.left]
        movsx   edx, [eax+TWinTemplateDT.top]
        mov     [.winrect.left], ecx
        mov     [.winrect.top], edx
        movzx   ecx, [eax+TWinTemplateDT.width]
        movzx   edx, [eax+TWinTemplateDT.height]
        add     ecx, [.winrect.left]
        add     edx, [.winrect.top]
        mov     [.winrect.right], ecx
        mov     [.winrect.bottom], edx

        lea     ecx, [.winrect]
        invoke  PtInRect, ecx, [.cursorpos.x], [.cursorpos.y]
        test    eax, eax
        jz      .unselectloop

        invoke  SendMessageW, [.hwnd], SZM_UNSELECTCONTROL, [esi+4*ebx+TArray.array], 0
        stdcall UpdateSizerSize, [.hwnd], edi

.endunselect:
        xor     eax, eax
        pop     ebx edi esi
        return


;-----------------------------------------------------------------------
oncase WM_LBUTTONUP
        invoke  ReleaseCapture
        invoke  ClipCursor, NULL

        xor     eax, eax
        pop     ebx edi esi
        return


;-----------------------------------------------------------------------
oncase WM_MOUSEMOVE
locals
  .point  POINT
  .delta POINT
  .delta2 POINT
  .hDefer dd ?
endl
        invoke  GetCapture
        cmp     eax, [.hwnd]
        jne     .endmousemove

; compute deltas
        movsx   eax, word [.lparam]
        movsx   ecx, word [.lparam+2]
        sub     eax, [edi+TSizer.dragXY.x]
        sub     ecx, [edi+TSizer.dragXY.y]
        mov     [.delta.x], eax
        mov     [.delta.y], ecx

        stdcall RoundToGrid, eax, [xGrid]
        mov     [.delta2.x], eax
        stdcall RoundToGrid, ecx, [yGrid]
        mov     [.delta2.y], eax
        or      eax, [.delta2.x]
        jz      .endmousemove

        mov     esi, [edi+TSizer.selected]
        mov     ebx, [esi+TArray.count]
        lea     esi, [esi+TArray.array]

        invoke  BeginDeferWindowPos, ebx
        mov     [.hDefer], eax

.selectedloop:
        dec     ebx
        js      .endselloop

        mov     eax, [esi]
        movsx   ecx, [eax+TWinTemplateDT.left]
        movsx   edx, [eax+TWinTemplateDT.top]
        mov     [.point.x], ecx
        mov     [.point.y], edx
        movsx   ecx, [eax+TWinTemplateDT.width]
        movsx   edx, [eax+TWinTemplateDT.height]
        add     ecx, [.point.x]
        add     edx, [.point.y]

        mov     eax, [.delta2.x]

        test    [edi+TSizer.moveX], 1
        jz      @f
        add     [.point.x], eax
@@:
        test    [edi+TSizer.moveX], 2
        jz      @f
        add     ecx, eax
@@:

        mov     eax, [.delta2.y]

        test    [edi+TSizer.moveY], 1
        jz      @f
        add     [.point.y], eax
@@:
        test    [edi+TSizer.moveY], 2
        jz      @f
        add     edx, eax
@@:
        sub     ecx, [.point.x]
        sub     edx, [.point.y]

        cmp     [edi+TSizer.moveX], 3
        je      .heightok

        cmp     ecx, 16
        jge     .widthok

        test    [edi+TSizer.moveX], 2
        jz      @f
        sub     ecx, 16
        add     [.point.x], ecx
@@:
        mov     ecx, 16

.widthok:
        cmp     edx, 16
        jge     .heightok

        test    [edi+TSizer.moveY], 2
        jz      @f
        sub     edx, 16
        add     [.point.y], edx
@@:
        mov     edx, 16

.heightok:
        push    SWP_NOZORDER or SWP_NOREDRAW
        push    edx
        push    ecx

        mov     eax, [esi]

        mov     [eax+TWinTemplateDT.width], cx
        mov     [eax+TWinTemplateDT.height], dx
        mov     ecx, [.point.x]
        mov     edx, [.point.y]
        push    edx
        push    ecx
        mov     [eax+TWinTemplateDT.left], cx
        mov     [eax+TWinTemplateDT.top], dx
        invoke  DeferWindowPos, [.hDefer], [eax+TWinTemplateDT.hwnd], 0

        add     esi, 4
        jmp     .selectedloop

.endselloop:
        invoke  EndDeferWindowPos, [.hDefer]
        stdcall UpdateSizerSize, [.hwnd], edi

.endmousemove:
; update the TSizer.dragXY
        lea     esi, [edi+TSizer.dragXY]
        invoke  GetCursorPos, esi
        invoke  ScreenToClient, [.hwnd], esi

        mov     ecx, [.delta.x]
        mov     edx, [.delta.y]
        sub     ecx, [.delta2.x]
        sub     edx, [.delta2.y]
        sub     [edi+TSizer.dragXY.x], ecx
        sub     [edi+TSizer.dragXY.y], edx

        xor     eax, eax
        pop     ebx edi esi
        return

;-----------------------------------------------------------------------
oncase WM_PAINT
  locals
    .paintstr PAINTSTRUCT
    .client   RECT
    .middle   RECT
    .half     dd ?
  endl
        lea     esi, [.paintstr]
        invoke  BeginPaint, [.hwnd], esi

        lea     eax, [.client]
        lea     ecx, [.middle]
        stdcall ComputeInternalRect, [.hwnd], eax, ecx, [SizerGripSize]

        mov     eax, [edi+TSizer.selected]
        cmp     [eax+TArray.count], 1
        jle     .regionok

; Draw frame around all selected objects in rectangle.
        invoke  CreateSolidBrush, [clSizerSize]
        push    eax
        invoke  FrameRgn, [esi+PAINTSTRUCT.hdc], [edi+TSizer.region], eax, 2, 2
        invoke  DeleteObject ; brush from the stack

; Draw dotted rectangle around the sizer.
        invoke  CreatePen, PS_DOT, 0, 0
        invoke  SelectObject, [esi+PAINTSTRUCT.hdc], eax
        push    eax

        invoke  GetStockObject, NULL_BRUSH
        invoke  SelectObject, [esi+PAINTSTRUCT.hdc], eax
        push    eax
        invoke  SetBkMode, [esi+PAINTSTRUCT.hdc], TRANSPARENT

        mov     eax, [SizerGripSize]
        sar     eax,1
        mov     [.half], eax

        mov     eax, [.client.right]
        mov     ecx, [.client.bottom]
        sub     eax, [.half]
        sub     ecx, [.half]

        invoke  Rectangle, [esi+PAINTSTRUCT.hdc], [.half], [.half], eax, ecx

        invoke  SelectObject, [esi+PAINTSTRUCT.hdc] ; old brush from the stack
        invoke  SelectObject, [esi+PAINTSTRUCT.hdc] ; old pen from the stack
        invoke  DeleteObject, eax


.regionok:
; Draw drag rectangles in the corners.
        mov     eax, [edi+TSizer.selected]
        cmp     [eax+TArray.count], 1
        jg      .dragok

        invoke  GetStockObject, BLACK_PEN
        invoke  SelectObject, [esi+PAINTSTRUCT.hdc], eax
        push    eax

        invoke  CreateSolidBrush, [clSizerSize]
        invoke  SelectObject, [esi+PAINTSTRUCT.hdc], eax
        push    eax

        invoke  Rectangle, [esi+PAINTSTRUCT.hdc], 0, 0, [SizerGripSize], [SizerGripSize]
        invoke  Rectangle, [esi+PAINTSTRUCT.hdc], 0, [.client.top], [SizerGripSize], [.client.bottom]
        invoke  Rectangle, [esi+PAINTSTRUCT.hdc], [.client.left], 0, [.client.right], [SizerGripSize]
        invoke  Rectangle, [esi+PAINTSTRUCT.hdc], [.client.left], [.client.top], [.client.right], [.client.bottom]

        invoke  Rectangle, [esi+PAINTSTRUCT.hdc], [.middle.left], 0, [.middle.right], [SizerGripSize]
        invoke  Rectangle, [esi+PAINTSTRUCT.hdc], 0, [.middle.top], [SizerGripSize], [.middle.bottom]
        invoke  Rectangle, [esi+PAINTSTRUCT.hdc], [.middle.left], [.client.top], [.middle.right], [.client.bottom]
        invoke  Rectangle, [esi+PAINTSTRUCT.hdc], [.client.left], [.middle.top], [.client.right], [.middle.bottom]

;        invoke  CreateSolidBrush, [clSizerMove]
;        invoke  SelectObject, [esi+PAINTSTRUCT.hdc], eax
;        invoke  DeleteObject, eax
;
;        invoke  Rectangle, [esi+PAINTSTRUCT.hdc], [.middle.left], [.middle.top], [.middle.right], [.middle.bottom]

        invoke  SelectObject, [esi+PAINTSTRUCT.hdc] ; old brush from the stack
        invoke  DeleteObject, eax

        invoke  SelectObject, [esi+PAINTSTRUCT.hdc] ; old pen from the stack

.dragok:
        invoke  EndPaint, [.hwnd], esi
        xor     eax, eax
        pop     ebx edi esi
        return

        enddispatch
endp


iglobal
label SizerCursors dword
      dd IDC_ARROW, IDC_ARROW,    IDC_ARROW,  IDC_ARROW
      dd IDC_ARROW, IDC_SIZENWSE, IDC_SIZENS, IDC_SIZENESW
      dd IDC_ARROW, IDC_SIZEWE,   IDC_ARROW,  IDC_SIZEWE
      dd IDC_ARROW, IDC_SIZENESW, IDC_SIZENS, IDC_SIZENWSE

label SizerXYInc byte
      db 3, 3, 3, 3
      db 3, 1, 0, 2
      db 3, 1, 3, 2
      db 3, 1, 0, 2
endg




proc ComputeDragKind, .hwnd, .width
.point POINT
.client RECT
.middle RECT
begin
        push    ebx

        lea     ecx, [.middle]
        lea     eax, [.client]
        stdcall ComputeInternalRect, [.hwnd], eax, ecx, [.width]

        lea     ebx, [.point]
        invoke  GetCursorPos, ebx
        invoke  ScreenToClient, [.hwnd], ebx

        xor     ebx, ebx
        mov     eax, [.point.x]
        mov     ecx, [.point.y]

        cmp     eax, [.width]
        jg      @f
        test    eax, eax
        js      .indexy
        mov     bl, 1
        jmp     .indexy

@@:
        cmp     eax, [.middle.right]
        jg      @f
        cmp     eax, [.middle.left]
        jl      .indexy
        mov     bl, 2
        jmp     .indexy

@@:
        cmp     eax, [.client.left]
        jl      .indexy
        cmp     eax, [.client.right]
        jg      .indexy

        mov     bl, 3

.indexy:
        cmp     ecx, [.width]
        jg      @f
        test    ecx, ecx
        js      .indexok
        mov     bh, 1
        jmp     .indexok

@@:
        cmp     ecx, [.middle.bottom]
        jg      @f
        cmp     ecx, [.middle.top]
        jl      .indexok
        mov     bh, 2
        jmp     .indexok

@@:
        cmp     ecx, [.client.top]
        jl      .indexok
        cmp     ecx, [.client.bottom]
        jg      .indexok

        mov     bh, 3

.indexok:
        mov     eax, ebx
        pop     ebx
        return
endp



proc ComputeInternalRect, .hwnd, .ptrClient, .ptrMiddle, .width
begin
        push    esi edi
        mov     esi, [.ptrClient]
        mov     edi, [.ptrMiddle]

        invoke  GetClientRect, [.hwnd], esi

        mov     eax, [esi+RECT.right]
        mov     ecx, [esi+RECT.bottom]
        sub     eax, [.width]
        sub     ecx, [.width]
        mov     [esi+RECT.left], eax
        mov     [esi+RECT.top], ecx

        mov     eax, [esi+RECT.right]
        mov     ecx, [esi+RECT.bottom]
        sub     eax, [.width]
        sub     ecx, [.width]
        sar     eax, 1
        sar     ecx, 1
        mov     [edi+RECT.left], eax
        mov     [edi+RECT.top], ecx
        add     eax, [.width]
        add     ecx, [.width]
        mov     [edi+RECT.right], eax
        mov     [edi+RECT.bottom], ecx

        pop     edi esi
        return
endp



proc UpdateSizerSize, .hWnd, .ptrSizer
.rectmax   RECT
.point1    POINT
.point2    POINT
.update    dd ?
.region    dd ?
.parent    dd ?

begin
        push    esi edi ebx

        invoke  GetParent, [.hWnd]
        mov     [.parent], eax

        mov     esi, [.ptrSizer]
        invoke  DeleteObject, [esi+TSizer.region]

        xor     eax, eax
        lea     edi, [.rectmax]
        mov     [edi+RECT.right], eax
        mov     [edi+RECT.bottom], eax
        mov     eax, $7fffffff
        mov     [edi+RECT.left], eax
        mov     [edi+RECT.top], eax

        xor     eax, eax
        invoke  CreateRectRgn, eax, eax, eax, eax
        mov     [.region], eax
        mov     [esi+TSizer.region], eax

; Old rectangle, that have to be erased.
        lea     ecx, [.point1]
        invoke  GetWindowRect, [.hWnd], ecx
        lea     ecx, [.point1]
        invoke  ScreenToClient, [.parent], ecx
        lea     ecx, [.point2]
        invoke  ScreenToClient, [.parent], ecx
        lea     ecx, [.point1]

        invoke  CreateRectRgnIndirect, ecx
        mov     [.update], eax

        mov     esi, [esi+TSizer.selected]
        mov     ebx, [esi+TArray.count]

.adjloop:
        dec     ebx
        js      .endloop

        mov     eax, [esi+4*ebx+TArray.array]

        movsx   ecx, [eax+TWinTemplateDT.left]
        movsx   edx, [eax+TWinTemplateDT.top]
        mov     [.point1.x], ecx
        mov     [.point1.y], edx

;[result.left] = MIN [result.left] [.rect.left]
        cmp     ecx, [edi+RECT.left]
        cmovg   ecx, [edi+RECT.left]
        mov     [edi+RECT.left], ecx

;[result.top] = MIN [result.top] [.rect.top]
        cmp     edx, [edi+RECT.top]
        cmovg   edx, [edi+RECT.top]
        mov     [edi+RECT.top], edx

        movsx   ecx, [eax+TWinTemplateDT.width]
        movsx   edx, [eax+TWinTemplateDT.height]
        add     ecx, [.point1.x]
        add     edx, [.point1.y]

;[result.right] = MAX [result.right] [.rect.right]
        cmp     ecx, [edi+RECT.right]
        cmovl   ecx, [edi+RECT.right]
        mov     [edi+RECT.right], ecx

;[result.bottom] = MAX [result.bottom] [.rect.bottom]
        cmp     edx, [edi+RECT.bottom]
        cmovl   edx, [edi+RECT.bottom]
        mov     [edi+RECT.bottom], edx

; Add rectangle to the selected region.
        invoke  CreateRectRgn, [.point1.x], [.point1.y], ecx, edx
        push    eax

        invoke  CombineRgn, [.region], [.region], eax, RGN_OR
        invoke  DeleteObject ; from the stack

; exclude children rectangles...
        push    esi ebx
        mov     eax, [esi+4*ebx+TArray.array]

        mov     esi, [eax+TWinTemplateDT.children]
        mov     ebx, [esi+TArray.count]

.childrenloop:
        dec     ebx
        js      .endchildren

        mov     eax, [esi+4*ebx+TArray.array]

        movsx   ecx, [eax+TWinTemplateDT.left]
        movsx   edx, [eax+TWinTemplateDT.top]
        add     ecx, [.point1.x]
        add     edx, [.point1.y]
        mov     [.point2.x], ecx
        mov     [.point2.y], edx
        movsx   ecx, [eax+TWinTemplateDT.width]
        movsx   edx, [eax+TWinTemplateDT.height]
        add     ecx, [.point2.x]
        add     edx, [.point2.y]

        invoke  CreateRectRgn, [.point2.x], [.point2.y], ecx, edx
        push    eax
        invoke   CombineRgn, [.region], [.region], eax, RGN_DIFF
        invoke  DeleteObject ; from the stack
        jmp     .childrenloop

.endchildren:
        pop     ebx esi
        jmp     .adjloop

.endloop:

; offset of the region
        mov     edx, [SizerGripSize]
        mov     eax, [edi+RECT.left]
        mov     ecx, [edi+RECT.top]
        neg     eax
        sar     edx, 1
        neg     ecx
        add     eax, edx
        add     ecx, edx

        invoke  OffsetRgn, [.region], eax, ecx
        cmp     eax, NULLREGION
        je      .hide

; Compute width, height, left and top
        mov     eax, [SizerGripSize]
        sar     eax, 1
        sub     [edi+RECT.left], eax
        sub     [edi+RECT.top], eax
        add     [edi+RECT.right], eax
        add     [edi+RECT.bottom], eax

        invoke  CreateRectRgnIndirect, edi
        push    eax
        invoke  CombineRgn, [.update], [.update], eax, RGN_OR
        invoke  DeleteObject ; from the stack

        mov     eax, [edi+RECT.left]
        mov     ecx, [edi+RECT.top]
        sub     [edi+RECT.right], eax
        sub     [edi+RECT.bottom], ecx

        mov     eax, [.ptrSizer]
        mov     eax, [eax+TSizer.selected]
        cmp     [eax+TArray.count], 1
        jne     @f

        lea     eax, [.point1]
        push    eax
        invoke  GetRgnBox, [.region], eax
        invoke  CreateRectRgnIndirect ; from the stack
        mov     ebx, eax
        invoke  CreateRectRgn, 0, 0, [edi+RECT.right], [edi+RECT.bottom]
        push    eax
        invoke  CombineRgn, ebx, eax, ebx, RGN_DIFF
        invoke  DeleteObject ; from the stack
        invoke  CombineRgn, [.region], [.region], ebx, RGN_OR
        invoke  DeleteObject, ebx

@@:
        invoke  SetWindowPos, [.hWnd], HWND_TOP, [edi+RECT.left], [edi+RECT.top], [edi+RECT.right], [edi+RECT.bottom], SWP_SHOWWINDOW or SWP_NOREDRAW or SWP_NOSENDCHANGING

        invoke  RedrawWindow, [.parent], NULL, [.update], RDW_ERASE or RDW_INVALIDATE or RDW_ERASENOW or RDW_UPDATENOW or RDW_ALLCHILDREN
        invoke  RedrawWindow, [.hWnd], NULL, NULL, RDW_ERASE or RDW_INVALIDATE or RDW_ERASENOW or RDW_UPDATENOW

        invoke  DeleteObject, [.update]
        pop     ebx edi esi
        return

.hide:
        invoke  ShowWindow, [.hWnd], SW_HIDE
        invoke  DeleteObject, [.update]
        pop     ebx edi esi
        return
endp



;-----------------------------------------------------------------
; Arguments:
;   eax = pointer to the TWinTemplateDT structure.
; Returns:
;   eax = handle of the TSizer control for given set of windows.
;-----------------------------------------------------------------
proc GetSizer
begin
.backloop:
        cmp     [eax+TWinTemplateDT.parent], 0
        je      .found
        mov     eax, [eax+TWinTemplateDT.parent]
        jmp     .backloop

.found:
        mov     eax, [eax+TWinTemplateDT.hSizer]
        return
endp



proc GetSelectionList, .ptrWinTemplate
begin
        mov     eax, [.ptrWinTemplate]
        test    eax, eax
        jz      .finish

        stdcall GetSizer
        test    eax, eax
        jz      .finish

        invoke  GetWindowLongW, eax, 0
        test    eax, eax
        jz      .finish

        mov     eax, [eax+TSizer.selected]

.finish:
        return
endp

