; _______________________________________________________________________________________
;|                                                                                       |
;| ..::FreshLib::..  Free, open source. Licensed under "BSD 2-clause" license."          |
;|_______________________________________________________________________________________|
;
;  Description:
;
;  Target OS: Windows
;
;  Dependencies:
;
;  Notes: Most of this library is actually pretty portable.
;         Here it will be widely tested and then back ported to FreshLib
;         with minimal effort.
;_________________________________________________________________________________________


winmessage SGM_REALIGN
winmessage SGM_AUTOSIZE


stOriginBR = $08    ; the origin of the cell splitter is on the right (or bottom)
                    ; edge of the cell.

; IMPORTANT! The following 2 values are MAGIC. Don't change!

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.

stAutosize =  1 shl 11

stMaxHidden = 1 shl 12 ; the pos is assumed to be equal to the max value. The splitter is
stHidden    = 1 shl 13 ; the pos is assumed to be 0 (but the real value is not cleared)
stRelative  = 1 shl 14 ; the pos field is a part of a whole (in 1/32768 units)
stJustGap   = 1 shl 15 ; the rectangle is splitted, but not resizeable.

struct TSplitRect
  .rect    RECT    ; the rectangle of the area.
  .spRect  RECT    ; rectangle of the splitter.
  .hWindow dd ?    ; handle of window, 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 ?
  .reserve 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
}


iglobal
  DrawSplitter  dd DrawSplitterDefault
endg



proc RealignGrid, .hwnd, .ptrSplitter, .ptrRect
.rect RECT
.hdc   dd ?
begin
        pushad


        mov     edi, [.ptrSplitter]
        mov     esi, [.ptrRect]

        invoke  GetDC, [.hwnd]
        mov     [.hdc], eax

        stdcall _DoRealign, [.hdc]

        invoke  InvalidateRect, [.hwnd], 0, FALSE

        invoke  ReleaseDC, [.hwnd], [.hdc]

;.finish:
        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, .hdc
.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     .resize_window

; There is split, so compute it.
        and     ecx, stVert            ; it is 0 for stHoriz and 4 for stVert

        mov     ebx, [esi+TSplitRect.rect.right+ecx]
        sub     ebx, [esi+TSplitRect.rect.left+ecx]     ; ebx = size of rect (x or y depending on type)
        mov     edx, [esi+TSplitRect.spWidth]

        test    [esi+TSplitRect.type], stHidden or stMaxHidden
        jz      .hidden_ok1
        xor     edx, edx
.hidden_ok1:

        sub     ebx, edx

        mov     eax, [esi+TSplitRect.pos]               ; limit the .pos value

        test    [esi+TSplitRect.type], stAutosize
        jz      .autosize_ok

        call    __GetSplitAutosize

.autosize_ok:

        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                ; EAX = position of the splitter.

        test    [esi+TSplitRect.type], stHidden
        jz      .hidden_ok2
        xor     eax, eax
.hidden_ok2:

        test    [esi+TSplitRect.type], stMaxHidden
        jz      .hidden_ok3

        mov     eax, [esi+TSplitRect.max]

.hidden_ok3:

        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                                     ; EDX is the width of the splitter
        neg     eax                                     ; EAX is the position of the splitter

.readyofs:
        add     eax, [.rect1.left+ecx]                  ; .left or .top, depending on the ECX (0 or 4)

        mov     [.rect1.right+ecx], eax                 ; .right or .bottom, depending on the ECX
        mov     [esi+TSplitRect.spRect.left+ecx], eax   ; spRect.left or spRect.top

        add     ecx, 8      ; right or bottom           ; ecx = 8 or 12
        and     ecx, $0f

        add     eax, edx
        mov     [.rect1.right+ecx], eax                 ; it is rect2.left or .top !!!!!!
        mov     [esi+TSplitRect.spRect.left+ecx], eax   ; spRect.right or spRect.bottom


        push    esi

        lea     esi, [.rect1]
        stdcall _DoRealign, [.hdc]

        lea     esi, [.rect2]
        stdcall _DoRealign, [.hdc]

        pop     esi

; Draw the splitter

        lea     eax, [esi+TSplitRect.spRect]
        stdcall [DrawSplitter], [.hdc], eax, [esi+TSplitRect.type]

        return


.resize_window:
        push    edi

        mov     ebx, [esi+TSplitRect.hWindow]
        test    ebx, ebx
        jz      .endresize

        invoke  IsWindow, ebx
        test    eax, eax
        jz      .endresize

        lea     edx, [.rect1]
        invoke  GetWindowRect, ebx, edx

        invoke  GetParent, ebx
        mov     edi, eax

        lea     edx, [.rect1.left]
        invoke  ScreenToClient, edi, edx

        lea     edx, [.rect1.right]
        invoke  ScreenToClient, edi, edx

        mov     eax, [.rect1.left]
        mov     ecx, [.rect1.top]
        sub     [.rect1.right], eax
        sub     [.rect1.bottom], ecx

        xor     edx, edx
        inc     edx

        mov     eax, [esi+TSplitRect.rect.right]
        mov     ecx, [esi+TSplitRect.rect.bottom]
        sub     eax, [esi+TSplitRect.rect.left]
        cmovle  eax, edx

        sub     ecx, [esi+TSplitRect.rect.top]
        cmovle  ecx, edx

        mov     edi, SWP_NOZORDER

        cmp     eax, [.rect1.right]
        jne     .sizeok

        cmp     ecx, [.rect1.bottom]
        jne     .sizeok

        or      edi, SWP_NOSIZE

.sizeok:
        mov     edx, [.rect1.left]
        cmp     edx, [esi+TSplitRect.rect.left]
        jne     .posok

        mov     edx, [.rect1.top]
        cmp     edx, [esi+TSplitRect.rect.top]
        jne     .posok

        or      edi, SWP_NOMOVE

.posok:

        test    edi, SWP_NOSIZE
        jz      .setit

        test    edi, SWP_NOMOVE
        jnz     .endresize

.setit:
;        OutputValue "Window handle: ", ebx, 16, 8
;        OutputValue "X=", [esi+TSplitRect.rect.left], 10, -1
;        OutputValue "Y=", [esi+TSplitRect.rect.top], 10, -1
;        OutputValue "W=", eax, 10, -1
;        OutputValue "H=", ecx, 10, -1
;        OutputValue "Flags=", edi, 16, 8

        invoke  SetWindowPos, ebx, 0, [esi+TSplitRect.rect.left], [esi+TSplitRect.rect.top], eax, ecx, edi
        invoke  UpdateWindow, ebx

.endresize:
        pop     edi
        return
endp


proc __GetSplitAutosize
.rect RECT
begin
        pushad
        mov     ebx, [esi+TSplitRect.hWindow]
        test    ebx, ebx
        jz      .finish

        invoke  SendMessageW, ebx, SGM_AUTOSIZE, 0, 0

        mov     ecx, eax
        movsx   eax, ax
        sar     ecx, 16         ; height

        test    [esi+TSplitRect.type], stHoriz
        cmovnz  ecx, eax                        ; here edx is the pos of the split

        mov     [esp+4*regEAX], ecx

.finish:
        popad
        return
endp



proc DrawSplitters, .hdc, .ptrSplitters
begin
        pushad
        mov     esi, [.ptrSplitters]
        mov     edi, [.hdc]
        call    _DoDrawSplitters
        popad
        return
endp


; esi - pointer to TSplitRect
; edi - hdc

proc _DoDrawSplitters
begin
        mov     ebx, esi
        add     esi, sizeof.TSplitRect

        test    [ebx+TSplitRect.type], stNone
        jnz     .exit

        lea     eax, [ebx+TSplitRect.spRect]
        stdcall [DrawSplitter], edi, eax, [ebx+TSplitRect.type]

        call    _DoDrawSplitters  ; first
        call    _DoDrawSplitters  ; second

.exit:
        return
endp



proc DrawSplitterDefault, .hdc, .pRect, .type
begin
        pushad

        test    [.type], stHidden
        jnz     .finish

        mov     eax, $2de3cb  ;$0f3dc6 brown   ;$ff80a0 lilac
        test    [.type], stJustGap
        jz      .color_ok

        jmp     .finish

        invoke  GetSysColor, COLOR_BTNFACE
;        mov     eax, $ff                       ; red color for debugging.

.color_ok:
        and     eax, $ffffff
        invoke  CreateSolidBrush, eax
        push    eax

        invoke  FillRect, [.hdc], [.pRect], eax

        invoke  DeleteObject ; from the stack

.finish:
        popad
        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

        clc
        test    [ebx+TSplitRect.type], stNone
        jnz     .exit

        lea     eax, [ebx+TSplitRect.spRect]

        stdcall PointInRect, eax, [edi+POINT.x], [edi+POINT.y]
        jc      .exit

        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 GetCtrlCell, .hwnd
begin
        pushad

        mov     ebx, [.hwnd]
        invoke  GetParent, ebx

        invoke  GetPropW, eax, [propSplitGrid]
        test    eax, eax
        jz      .not_found

        mov     edi, eax
        lea     esi, [edi+TArray.array]
        xor     ecx, ecx

.loop:
        cmp     ecx, [edi+TArray.count]
        jae     .not_found

        cmp     [esi+TSplitRect.hWindow], ebx
        je      .found

        add     esi, sizeof.TSplitRect
        inc     ecx
        jmp     .loop

.found:
        mov     [esp+4*regEAX], ecx
        clc
        popad
        return

.not_found:
        stc
        popad
        return
endp




proc GetCellRect, .hwnd, .cell
begin
        push    ecx edx

        invoke  GetPropW, [.hwnd], [propSplitGrid]
        test    eax, eax
        jz      .error

        stdcall GetArrayItem, eax, [.cell]

.finish:
        pop     edx ecx
        return

.error:
        stc
        jmp     .finish
endp



proc SetCellPos, .hwnd, .cell, .pos
begin
        pushad

        invoke  GetPropW, [.hwnd], [propSplitGrid]
        test    eax, eax
        jz      .error

        lea     esi, [eax+TArray.array]
        mov     edi, esi

        mov     eax, [.cell]
        imul    eax, sizeof.TSplitRect
        add     esi, eax
        xor     ecx, ecx

; first search for the split element of this cell

.loop:
        sub     esi, sizeof.TSplitRect
        cmp     esi, edi
        jb      .error

        bt      [esi+TSplitRect.type], 7        ; stNone
        sbb     edx, edx                        ; -1 if the element is a cell and 0 if split
        lea     edx, [2*edx+1]                  ; -1 if the element is a cell and +1 if split

        add     ecx, edx
        jl      .loop           ; here, if ecx > 0 it is the first cell after the split, if ecx == 0 it is the second cell.

; found
        mov     eax, [.pos]
        xchg    eax, [esi+TSplitRect.pos]
        cmp     eax, [esi+TSplitRect.pos]
        je      .finish

        stdcall RealignGrid, [.hwnd], esi, esi   ; realign on its own rectangle.

.finish:
        clc
        popad
        return

.error:
        stc
        popad
        return
endp




proc SetCellHidden, .hwnd, .cell, .fDisplay
begin
        pushad

        invoke  GetPropW, [.hwnd], [propSplitGrid]
        test    eax, eax
        jz      .error

        lea     esi, [eax+TArray.array]
        mov     edi, esi

        mov     eax, [.cell]
        imul    eax, sizeof.TSplitRect
        add     esi, eax
        xor     ecx, ecx

; first search for the split element of this cell

.loop:
        sub     esi, sizeof.TSplitRect
        cmp     esi, edi
        jb      .error

        bt      [esi+TSplitRect.type], 7        ; stNone
        sbb     edx, edx                        ; -1 if the element is a cell and 0 if split
        lea     edx, [2*edx+1]                  ; -1 if the element is a cell and +1 if split

        add     ecx, edx
        jl      .loop

; here ecx =  0 if the cell is the second cell
;      ecx = +1 if the cell is the first cell

        test    [esi+TSplitRect.type], stOriginBR
        jz      @f
        xor     ecx, 1          ; reverse it if the split is stOriginBR
@@:

        add     ecx, 12         ; stMaxHidden = 2^12; stHidden = 2^13
        xor     edx, edx
        inc     edx
        shl     edx, cl         ; edx = stHidden or stMaxHidden depending on the cell that has to be hidden or shown.
        mov     ecx, edx
        not     ecx             ; AND mask.

; found
        cmp     [.fDisplay], 0
        sete    al
        shr     al, 1
        sbb     eax, eax        ; eax = $ffffffff or 0 depending on the .fDisplay flag.

        and     edx, eax        ; the OR mask.

        and     [esi+TSplitRect.type], ecx
        or      [esi+TSplitRect.type], edx ; set only one.

        stdcall RealignGrid, [.hwnd], esi, esi   ; realign on its own rectangle.
        clc
        popad
        return

.error:
        stc
        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




proc SetSplitGrid, .hwnd, .pSGTemplate
.rect RECT
begin
        pushad

        invoke  GetPropW, [.hwnd], [propSplitGrid]
        test    eax, eax
        jz      .prev_ok

        stdcall FreeMem, eax
        invoke  RemovePropW, [.hwnd], [propSplitGrid]

.prev_ok:
        stdcall ReadSplitGridTemplate, [.pSGTemplate]
        test    eax, eax
        jz      .finish

        mov     edi, eax

        push    [.hwnd]
        pop     [edi+TArray.lparam]

        invoke  SetPropW, [.hwnd], [propSplitGrid], edi
        lea     edi, [edi+TArray.array]

        invoke  SendMessageW, [.hwnd], SGM_REALIGN, 0, 0

.finish:
        popad
        return
endp




proc AttachToCell, .hwnd, .hParent, .cell
.rect RECT
begin
        pushad

        invoke  GetPropW, [.hParent], [propSplitGrid]
        test    eax, eax
        jz      .error

        lea     edi, [eax+TArray.array]

        mov     eax, [.cell]
        imul    eax, sizeof.TSplitRect

        lea     ebx, [edi+eax]          ; pointer to TSplitRect

        push    [.hwnd]
        pop     [ebx+TSplitRect.hWindow]

        stdcall RealignGrid, [.hParent], ebx, ebx

;        mov     eax, [ebx+TSplitRect.rect.right]
;        mov     ecx, [ebx+TSplitRect.rect.bottom]
;        sub     eax, [ebx+TSplitRect.rect.left]
;        sub     ecx, [ebx+TSplitRect.rect.top]
;
;        invoke  SetWindowPos, [.hwnd], 0, [ebx+TSplitRect.rect.left], [ebx+TSplitRect.rect.top], eax, ecx, SWP_NOZORDER

        clc
        popad
        return

.error:
        stc
        popad
        return
endp




proc AttachToCellDlgItem, .hwnd, .id, .cell
begin
        invoke  GetDlgItem, [.hwnd], [.id]
        stdcall AttachToCell, eax, [.hwnd], [.cell]
        return
endp



proc SplitGridWinProc, .hwnd, .wmsg, .wparam, .lparam
  .ps PAINTSTRUCT
  .rect  RECT
  .pnt   POINT
begin
        invoke  GetPropW, [.hwnd], [propSplitGrid]
        test    eax, eax
        jz      .ondefault

        lea     edi, [eax+TArray.array]
        dispatch [.wmsg]

.ondefault:
        stc
        return


;----------------------------------------------------------------------

oncase WM_DESTROY

        stdcall SetSplitGrid, [.hwnd], 0        ; free the existing splitgrid.

        stc
        return

;----------------------------------------------------------------------

oncase WM_LBUTTONDOWN

        movsx   eax, word [.lparam]
        movsx   ecx, word [.lparam+2]
        mov     [.pnt.x], eax
        mov     [.pnt.y], ecx

        lea     eax, [.pnt]
        stdcall FindSplitter, edi, eax
        jnc     .ondefault

        test    [eax+TSplitRect.type], stJustGap
        jnz     .ondefault

        mov     esi, eax
        invoke  SetPropW, [.hwnd], [propSplitterResize], esi
        invoke  SetCapture, [.hwnd]

        lea     edi, [.rect]
        mov     ecx, 4
        rep movsd

        lea     edi, [.rect]
        invoke  ClientToScreen, [.hwnd], edi
        add     edi, 8
        invoke  ClientToScreen, [.hwnd], edi
        sub     edi, 8
        invoke  ClipCursor, edi

        xor     eax, eax
        clc
        return

;----------------------------------------------------------------

oncase WM_MOUSEMOVE

        invoke  GetCapture
        cmp     eax, [.hwnd]
        jne     .ondefault

        invoke  GetPropW, [.hwnd], [propSplitterResize]
        test    eax, eax
        jz      .ondefault

        mov     esi, eax        ; splitter to resize
        mov     ecx, [esi+TSplitRect.type]
        and     ecx, stVert
        mov     eax, ecx
        shr     eax, 1
        movsx   eax, word [.lparam+eax] ; the respective coordinate.

        sub     eax, [esi+TSplitRect.rect.left+ecx]

        test    [esi+TSplitRect.type], stOriginBR
        jz      .sizeok

        mov     edx, [esi+TSplitRect.rect.right+ecx]
        sub     edx, [esi+TSplitRect.rect.left+ecx]
        sub     eax, edx
        neg     eax

        sub     eax, [esi+TSplitRect.spWidth]

.sizeok:
        test    [esi+TSplitRect.type], stRelative
        jz      .posok

        cdq
        mov     ebx, $8000
        imul    ebx

        mov     ebx, [esi+ecx+TSplitRect.rect.right]
        sub     ebx, [esi+ecx+TSplitRect.rect.left]     ; size of rect (x or y depending on type)

        idiv    ebx

.posok:
        mov     [esi+TSplitRect.pos], eax
        stdcall RealignGrid, [.hwnd], esi, esi

        xor     eax, eax
        clc
        return


;----------------------------------------------------------------------

oncase WM_LBUTTONUP

        invoke  GetCapture
        cmp     eax, [.hwnd]
        jne     .ondefault

        invoke  RemovePropW, [.hwnd], [propSplitterResize]
        invoke  ReleaseCapture
        invoke  ClipCursor, NULL

        jmp     .ondefault

;------------------------------------------------------------------------

oncase WM_SETCURSOR

        lea     esi, [.pnt]
        invoke  GetCursorPos, esi
        invoke  ScreenToClient, [.hwnd], esi

        stdcall FindSplitter, edi, esi
        jnc     .ondefault

        test    [eax+TSplitRect.type], stJustGap
        jnz     .ondefault

        mov     ecx, IDC_SIZEWE
        mov     edx, IDC_SIZENS
        test    [eax+TSplitRect.type], stVert
        cmovnz  ecx, edx

        invoke  LoadCursorW, 0, ecx
        invoke  SetCursor, eax

        clc
        return


;------------------------------------------------------------------------

oncase WM_PAINT

        test    [edi+TSplitRect.type], stNone
        jnz     .ondefault

        lea     ebx, [.ps]
        invoke  BeginPaint, [.hwnd], ebx

        stdcall DrawSplitters, [.ps.hdc], edi

        invoke  EndPaint, [.hwnd], ebx

        xor     eax, eax
        clc
        return

;------------------------------------------------------------------------

;oncase WM_WINDOWPOSCHANGED
;
;        mov     ebx, [.lparam]
;        mov     ecx, [ebx+WINDOWPOS.flags]
;        test    ecx, SWP_HIDEWINDOW
;        jnz     .ondefault
;
;        test    ecx, SWP_NOSIZE
;        jnz     .ondefault
;
;        invoke  SendMessageW, [.hwnd], FM_REALIGN, 0, 0
;
;        xor     eax, eax
;        clc
;        return


oncase WM_SIZE

        cmp     [.wparam], SIZE_RESTORED
        je      .resize

        cmp     [.wparam], SIZE_MAXIMIZED
        jne     .ondefault

.resize:
        invoke  SendMessageW, [.hwnd], SGM_REALIGN, 0, 0

        stc
        return


;------------------------------------------------------------------------

oncase SGM_REALIGN

        lea     esi, [.rect]
        invoke  GetClientRect, [.hwnd], esi

        stdcall RealignGrid, [.hwnd], edi, esi

        clc
        return


        enddispatch

endp



proc OnRealignWithPadding, .hwnd, .padLeft, .padTop, .padRight, .padBottom
.rect RECT
begin
        pushad

        invoke  GetPropW, [.hwnd], [propSplitGrid]
        test    eax, eax
        jz      .exit

        lea     edi, [eax+TArray.array]

        lea     esi, [.rect]
        invoke  GetClientRect, [.hwnd], esi

        mov     eax, [.rect.left]
        mov     ebx, [.rect.top]
        mov     ecx, [.rect.right]
        mov     edx, [.rect.bottom]

        sub     ecx, [.padRight]
        sub     edx, [.padBottom]

        cmp     ecx, eax
        cmovl   ecx, eax

        cmp     edx, ebx
        cmovl   edx, ebx

        add     eax, [.padLeft]
        add     ebx, [.padTop]

        cmp     eax, ecx
        cmovg   eax, ecx

        cmp     ebx, edx
        cmovg   ebx, edx

        mov     [.rect.left], eax
        mov     [.rect.top], ebx
        mov     [.rect.right], ecx
        mov     [.rect.bottom], edx

        stdcall RealignGrid, [.hwnd], edi, esi

.exit:
        popad
        return
endp