;*********************************************
; This is code for universal splitter control
; (C)2003 John Found
; It MUST be fixed in order to be added to the
; Fresh visual controls.
;*********************************************

iglobal
  cSplitterClassName du 'TSplitter',0
endg

;*************************************************************************
; Registers class TSplitter
;*************************************************************************
initialize RegisterSplitterClass
.wc WNDCLASS
begin
        xor     eax,eax
        mov     [.wc.style], CS_DBLCLKS or CS_PARENTDC or CS_VREDRAW or CS_HREDRAW
        mov     [.wc.lpfnWndProc], SplitterProc
        mov     [.wc.cbClsExtra], eax
        mov     [.wc.cbWndExtra], 4

        mov     [.wc.hIcon],eax
        mov     [.wc.hCursor],eax
        mov     [.wc.hbrBackground], eax
        mov     [.wc.lpszMenuName], eax
        mov     [.wc.lpszClassName], cSplitterClassName

        invoke  GetModuleHandleW, eax
        mov     [.wc.hInstance],eax

        lea     eax,[.wc]
        invoke  RegisterClassW,eax

        return
endp


proc CreateSplitter, .hControl, .flagVisible, .CursorV, .CursorH
begin
        push    ebx esi
        xor     ebx, ebx

        invoke  GetModuleHandleW, ebx
        mov     esi, eax

        invoke  GetParent, [.hControl]
        test    eax, eax
        jz      .finish

        mov     ecx, WS_CHILD or WS_CLIPSIBLINGS
        cmp     [.flagVisible], FALSE
        je      @f
        or      ecx, WS_VISIBLE
@@:
        invoke  CreateWindowExW, ebx, cSplitterClassName, ebx,       \
                                ecx,                                \
                                ebx, ebx, 20, 20,                 \
                                eax, ebx, esi, [.hControl]
        push    eax
        invoke  SendMessageW, eax, SPM_SETCURSORS, [.CursorV], [.CursorH]
        pop     eax
.finish:
        pop     esi ebx
        return
endp

;*************************************************************************
; The window proc for TSplitter control.
;*************************************************************************
proc SplitterProc, .hwnd, .wmsg, .wparam, .lparam

.ctrl   dd      ?
.rect   RECT
.pnt    POINT
.pntstr PAINTSTRUCT

begin
        push    esi edi ebx

        mov     ebx,[.wmsg]
        call    JumpTo
        MessageList                             \
          WM_CREATE,            .create,        \
          WM_DESTROY,           .destroy,       \
          WM_WINDOWPOSCHANGING, .poschanging,   \
          AM_ALIGNCHANGED,      .alignchanged,  \
          WM_MOUSEMOVE,         .mousemove,     \
          WM_LBUTTONDOWN,       .buttondown,    \
          WM_LBUTTONUP,         .buttonup,      \
          WM_SETCURSOR,         .setcursor,     \
          WM_ERASEBKGND,        .eraseback,     \
          SPM_SETCONTROL,       .setcontrol,    \
          SPM_SETCURSORS,       .setcursors,    \
          SPM_SETMAXMIN,        .setmaxmin

.default:
        invoke  DefWindowProcW, [.hwnd], [.wmsg], [.wparam], [.lparam]
        jmp     .finish

;***************************************************************************
.setmaxmin:
        invoke  GetWindowLongW, [.hwnd], 0
        mov     ecx, [.wparam]
        mov     edx, [.lparam]
        mov     [eax+TSplitter.MinSize], ecx
        mov     [eax+TSplitter.MaxSize], edx
        jmp     .finishdone

;***************************************************************************
.setcontrol:
        cmp     [.wparam],0
        jz      .finishdone

        invoke  GetParent, [.wparam]
        invoke  SetParent, [.hwnd], eax

        invoke  GetWindowLongW, [.hwnd], 0
        push    [.wparam]
        pop     [eax+TSplitter.Control]

        invoke  GetPropW, [.wparam], [propAlign]
        stdcall SetAlign, [.hwnd], eax

        xor     ebx, ebx
        invoke  SetWindowPos, [.hwnd], [.wparam], ebx, ebx, ebx, ebx, SWP_NOMOVE or SWP_SHOWWINDOW
        stdcall AlignSiblings, [.hwnd]

        invoke  IsWindowVisible, [.wparam]
        invoke  ShowWindow, [.hwnd], eax

        jmp     .finishdone

;***************************************************************************
.setcursors:
        invoke  GetWindowLongW, [.hwnd], 0
        push    [.wparam]
        push    [.lparam]
        pop     [eax+TSplitter.crHorizontal]
        pop     [eax+TSplitter.crVertical]
        jmp     .finishdone

;***************************************************************************
.mousemove:
        invoke  GetCapture
        cmp     eax,[.hwnd]
        jne     .finishdone

        invoke  GetWindowLongW,[.hwnd], 0
        push    [eax+TSplitter.Control]
        pop     [.ctrl]
        movsx   esi,word [.lparam]
        movsx   edi,word [.lparam+2]

        cmp     [eax+TSplitter.Orientation], soVertical
        je      .movex
        cmp     [eax+TSplitter.Orientation], soHorizontal
        je      .movey

        xor     esi,esi
        xor     edi,edi
        jz      .domove

.movex:
        sub     esi,[eax+TSplitter.Hold.x]
        xor     edi,edi
        jmp     .domove

.movey:
        sub     edi,[eax+TSplitter.Hold.y]
        xor     esi,esi

.domove:
        mov     [.pnt.x],esi
        mov     [.pnt.y],edi
        lea     ebx,[.pnt]
        mov     edi,eax         ; Address of TSplitter structure

        invoke  ClientToScreen,[.hwnd],ebx
        invoke  GetParent, [.hwnd]
        invoke  ScreenToClient,eax,ebx

; there is no need to move the splitter itself. The align system will move it automaticaly.
;       invoke  SetWindowPos,[.hwnd],NULL,[.pnt.x],[.pnt.y],0,0,SWP_NOSIZE or SWP_NOZORDER
; resize the control

        lea     esi,[.rect]
        invoke  GetWindowRect,[.ctrl], esi
        invoke  GetParent,[.ctrl]
        mov     ebx,eax

        invoke  ScreenToClient,ebx, esi
        add     esi,8
        invoke  ScreenToClient,ebx,esi

        invoke  GetPropW, [.ctrl], [propAlign]
        mov     ecx,eax

        mov     edx,[edi+TSplitter.MinSize]
        mov     ebx,[edi+TSplitter.MaxSize]

        loop    @f

;.sizeLeft:
        add     edx, [.rect.left]
        add     ebx, [.rect.left]

        mov     eax,[.pnt.x]
        cmp     eax,edx
        jge     .cmx1
        mov     eax,edx
.cmx1:
        cmp     eax,ebx
        jle     .cmx2
        mov     eax,ebx
.cmx2:
        mov     [.rect.right], eax
        jmp     .dosize

@@:     loop    @f
;.sizeRight:
        sub     edx,[.rect.right]
        sub     ebx,[.rect.right]
        neg     edx                     ; Max coordinate
        neg     ebx                     ; Min coordinate

        mov     eax,[.pnt.x]
        add     eax,[edi+TSplitter.Width]

        cmp     eax,ebx
        jge     .cmx3
        mov     eax,ebx
.cmx3:
        cmp     eax,edx
        jle     .cmx4
        mov     eax,edx
.cmx4:
        mov     [.rect.left],eax
        jmp     .dosize

@@:     loop    @f
;.sizeTop:
        add     edx,[.rect.top]
        add     ebx,[.rect.top]

        mov     eax,[.pnt.y]

        cmp     eax,edx
        jge     .cmy1
        mov     eax,edx
.cmy1:
        cmp     eax,ebx
        jle     .cmy2
        mov     eax,ebx
.cmy2:
        mov     [.rect.bottom],eax
        jmp     .dosize

@@:     loop    @f
;.sizeBottom:
        sub     edx,[.rect.bottom]
        sub     ebx,[.rect.bottom]
        neg     edx                     ; Max coordinate
        neg     ebx                     ; Min coordinate

        mov     eax,[.pnt.y]
        add     eax,[edi+TSplitter.Width]

        cmp     eax,ebx
        jge     .cmy3
        mov     eax,ebx
.cmy3:
        cmp     eax,edx
        jle     .cmy4
        mov     eax,edx
.cmy4:
        mov     [.rect.top],eax

.dosize:
        mov     eax,[.rect.right]
        mov     ebx,[.rect.bottom]
        sub     eax,[.rect.left]
        sub     ebx,[.rect.top]

        invoke  SetWindowPos, [.ctrl], NULL, [.rect.left], [.rect.top], eax, ebx, SWP_NOZORDER
        stdcall AlignSiblings, [.ctrl]
@@:
        jmp     .finishdone

;**************************************************************************

.buttondown:
        invoke  SetCapture, [.hwnd]
        invoke  GetWindowLongW,  [.hwnd], GWL_HWNDPARENT

        mov     edi,eax
        lea     esi,[.rect]

        invoke  GetClientRect, edi, esi
        invoke  ClientToScreen, edi, esi
        add     esi,8
        invoke  ClientToScreen, edi, esi
        sub     esi,8
        invoke  ClipCursor, esi

        invoke  GetWindowLongW, [.hwnd], 0
        movzx   esi, word [.lparam]
        movzx   edi, word [.lparam+2]
        mov     [eax+TSplitter.Hold.x],esi
        mov     [eax+TSplitter.Hold.y],edi
        jmp     .finishdone

;**************************************************************************

.buttonup:

        invoke  ReleaseCapture
        invoke  ClipCursor,NULL
        jmp     .finishdone

;**************************************************************************

.create:
        stdcall GetMem, sizeof.TSplitter
        mov     esi,eax

        invoke  SetWindowLongW, [.hwnd], 0, esi

        mov     [esi+TSplitter.Width],4
        mov     [esi+TSplitter.Orientation],soNone
        mov     [esi+TSplitter.MinSize],$10
        mov     [esi+TSplitter.MaxSize],$120
        mov     [esi+TSplitter.crVertical], IDC_SIZEWE or $ffff0000
        mov     [esi+TSplitter.crHorizontal], IDC_SIZENS or $ffff0000

        mov     eax, [.lparam]
        mov     eax, [eax+CREATESTRUCT.lpCreateParams]
        test    eax, eax
        jz      .finishdone

        invoke  SendMessageW, [.hwnd], SPM_SETCONTROL, eax, eax
        jmp     .finishdone

;**************************************************************************

.destroy:
        invoke  GetWindowLongW,[.hwnd],0
        mov     esi,eax
        stdcall FreeMem, esi
        jmp     .finishdone

;**************************************************************************
.poschanging:
        invoke  GetWindowLongW,[.hwnd],0
        mov     esi,eax                         ; Pointer of TSplitter
        mov     edi,[.lparam]

        mov     ecx, [esi+TSplitter.Orientation]
        loop    @f
; soVertical
        push    [esi+TSplitter.Width]
        pop     [edi+WINDOWPOS.cx]
        jmp     .finishdone

@@:     loop    @f
; soHorizontal
        push    [esi+TSplitter.Width]
        pop     [edi+WINDOWPOS.cy]
@@:
; soNone
        jmp     .finishdone
;**************************************************************************

.alignchanged:
        invoke  GetWindowLongW,[.hwnd],0
        cmp     [.wparam],waLeft
        je      .setvert
        cmp     [.wparam],waRight
        je      .setvert
        cmp     [.wparam],waTop
        je      .sethorz
        cmp     [.wparam],waBottom
        je      .sethorz

        mov     [eax+TSplitter.Orientation],soNone
        jmp     .finishdone

.setvert:
        mov     [eax+TSplitter.Orientation],soVertical
        jmp     .finishdone

.sethorz:
        mov     [eax+TSplitter.Orientation],soHorizontal
        jmp     .finishdone

;**************************************************************************

.setcursor:
        invoke  GetWindowLongW,[.hwnd],0
        mov     ecx,[eax+TSplitter.Orientation]
        xor     edx,edx
        jecxz   @f
        mov     edx, [eax+TSplitter.crVertical + 4*ecx -4]
@@:
        push    edx
        and     dword [esp], $ffff
        xor     eax, eax
        test    edx, edx
        js      .loadit

        invoke  GetModuleHandleW, eax

.loadit:
        push    eax
        invoke  LoadCursorW      ; arguments are in the stack.
        invoke  SetCursor,eax

        jmp     .finishdone

;**************************************************************************

.eraseback:
        lea     edi, [.rect]
        invoke  GetClientRect, [.hwnd], edi
        invoke  DrawEdge, [.wparam], edi, EDGE_ETCHED, BF_RECT or BF_MIDDLE
        xor     eax,eax
        inc     eax
        pop     ebx edi esi
        return

;**************************************************************************
.finishdone:
        xor     eax,eax
.finish:
        pop     ebx edi esi
        return
endp


