proc CreateFormEditor, .ptrOpenFile, .hTemplate
begin
        push    ebx esi edi

        stdcall CreateAsmEdit, [.ptrOpenFile], [.hTemplate], FormEditorProc
        jc      .error

        xor     eax, eax
        pop     edi esi ebx
        return

.error:
        test    eax, eax
        jnz     .errorload

        invoke  GetLastError
        test    eax, eax
        jnz     .errorload

        or      eax, -1         ; general error

.errorload:
        stc
        pop     edi esi ebx
        return
endp


iglobal
; properties for internal use...
  property propOpenFileStructure, 'OpenFileStructure' ; This is pointer to TOpenFile structure of the edited file.
  property propWinTemplate, 'WinTemplate'
  property propVisualMode, 'VisualMode'  ; 0 - view source, 1 - view form, 2 - pure text mode.


  cFormPrefix   du ";<ff", 13, 10, 0
  cFormSuffix   du ";ff>", 13, 10, 0


endg


proc FormEditorProc, .hwnd, .wmsg, .wparam, .lparam
begin

; prolog executed before message dispatcher
        invoke  GetPropW, [.hwnd], [propOpenFileStructure]
        mov     edi, eax

; message dispatcher

        mov     ebx, [.wmsg]
        dispatch ebx

        stc
        return

; Message handlers
;-----------------------------------------------------------------------
; Message handlers inherited from Source editor
oncase WM_DROPFILES
oncase WM_KEYDOWN
oncase WM_LBUTTONDOWN
oncase WM_RBUTTONDOWN
oncase WM_KILLFOCUS

oncase CCM_UPDATECCPOS
oncase CCM_UPDATEPAPOS

oncase WM_MEASUREITEM
oncase WM_DRAWITEM

oncase WM_VSCROLL
oncase WM_HSCROLL
        stdcall SourceEditProc, [.hwnd], [.wmsg], [.wparam], [.lparam]
        return


oncase FEM_SWITCHMODE
        invoke  GetPropW, [.hwnd], [propWinTemplate]
        test    eax, eax
        jz      .end_switch

        mov     ebx, [eax+TWinTemplateDT.hwnd]
        test    ebx, ebx
        jz      .end_switch

        mov     esi, [.wparam]
        cmp     esi, 2
        jb      .set_mode

        invoke  IsWindowVisible, ebx
        xor     eax, 1
        mov     esi, eax

.set_mode:
        invoke  SetPropW, [.hwnd], [propVisualMode], esi
        invoke  ShowWindow, ebx, esi

        mov     eax, ebx
        test    esi, esi
        cmovz   eax, [.hwnd]

        invoke  SetFocus, eax

.end_switch:
        clc
        return


;        invoke  GetPropW, [.hwnd], [propVisualMode]
;        mov     ebx, eax
;        xor     ebx, 1
;
;; show source
;        invoke  SetPropW, [.hwnd], [propVisualMode], ebx
;
;        test    ebx, ebx
;        jz      .showsource
;
;        invoke  GetPropW, [.hwnd], [propWinTemplate]
;        invoke  SetWindowPos, [eax+TWinTemplateDT.hwnd], HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOMOVE or SWP_SHOWWINDOW
;        clc
;        return
;
;.showsource:
;        invoke  GetPropW, [.hwnd], [propWinTemplate]
;        invoke  SetWindowPos, [eax+TWinTemplateDT.hwnd], 0, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOMOVE or SWP_HIDEWINDOW or SWP_NOZORDER
;
;        invoke  SetFocus, [.hwnd]
;        clc
;        return

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

oncase WM_SETFOCUS

        invoke  SetPropW, [.hwnd], [propVisualMode], 0

        stc
        return

;-----------------------------------------------------------------------
;oncase WM_COMMAND
;        invoke  GetParent, [.hwnd]
;        invoke  SendMessageW, eax, [.wmsg], [.wparam], [.lparam]
;        clc
;        return

;-----------------------------------------------------------------------
oncase CEM_LOADFILE

locals
  .formname dd ?
  .forfree  dd ?
  .codepg   dd ?
endl

cBaseTemplateFile text '%fresh%/IDE/templates/complex.asm'


        mov     [.formname], 0  ; the name is from the loaded source.
        mov     [.forfree], 0

        cmp     [.wparam], 0
        jne     .load_from_file

        cmp     [edi+TOpenFile.fNeverSaved], 0
        je      .load_from_file

        mov     [.formname], cFormNameNone

        stdcall ConvertAliasString, cBaseTemplateFile
        push    eax
        stdcall LoadBinaryFile, eax
        stdcall StrDel ; from the stack
        jc      .finish_load
        jmp     .formloaded


.load_from_file:
        mov     eax, [.wparam]
        test    eax, eax
        jnz     @f
        mov     eax, [edi+TOpenFile.hFileName]
@@:
        stdcall StrPtr, eax
        stdcall LoadBinaryFile, eax
        jc      .finish_load

.formloaded:
        mov     esi, eax

        stdcall InteractivelyConvertAnsiText, esi, -1
        jc      .finish_load

        mov     [.codepg], edx        ; the code page
        stdcall FreeMem, esi
        mov     esi, eax

        invoke  SendMessageW, [.hwnd], WM_SETTEXT, 0, esi

        stdcall WideCharToUtf8, esi
        mov     [.forfree], eax

        stdcall FreeMem, esi
        stdcall StrPtr, eax
        mov     esi, eax

        xor     ebx, ebx
        cmp     dword [esi], ';<ff'
        jne     .template_compiled

        stdcall SkipToNextLine

; Creates TWinTemplateDT for the form

        stdcall CompileSourceTemplate, esi
        mov     ebx, eax
        test    ebx, ebx
        jz      .template_compiled

        mov     [ebx+TWinTemplateDT.ptrFile], edi
        invoke  SetPropW, [.hwnd], [propWinTemplate], ebx
        stdcall CreateDesignWindow, ebx

.template_compiled:

        invoke  SendMessageW, [.hwnd], AEM_SETMODIFIED, FALSE, 0

        test    ebx, ebx
        jz      .read_only_ok

        stdcall CountDesignWindows, ebx
        add     eax, 2

        invoke  SendMessageW, [.hwnd], AEM_READONLY, eax, 0

        invoke  SendMessageW, [hPropEditor], PEM_SETCONTROL, ebx, 0
        invoke  SendMessageW, [hPropEditor], PEM_SETUPDATEPROC, 0, CreateDesignWindow

.read_only_ok:

        cmp     [edi+TOpenFile.fNeverSaved], 0
        jne     .MRUOK

        stdcall AddToMRUList, [ptrMRUFiles], [edi+TOpenFile.hFileName]

.MRUOK:
        cmp     [.codepg], CP_UTF8
        je      .codepg_ok

; set the file modified and to be "save as"

        mov     [edi+TOpenFile.fNeverSaved], TRUE
        invoke  SendMessageW, [.hwnd], _CEM_SETMODIFIED, TRUE, 0

.codepg_ok:
        xor     eax, eax

.finish_load:
        stdcall StrDel, [.forfree]
        clc
        return



;-----------------------------------------------------------------------
oncase _CEM_GETTEXT
locals
  .pos AEPOS
  .oldpos AEPOS
  .oldmode dd ?
  .si SCROLLINFO
endl

        mov     ebx, [.lparam]
        test    ebx, ebx
        jz      .errortext

        mov     [ebx+TInMemoryFile.fAscii], TRUE

        invoke  GetPropW, [.hwnd], [propWinTemplate]
        test    eax, eax
        jz      .errortext

        mov     edi, eax
        stdcall CreateSourceTemplate, edi
        mov     esi, eax                ; string with source header.


        invoke  SendMessageW, [.hwnd], AEM_READONLY, 0, 0
        mov     ebx, eax

        invoke  SendMessageW, [.hwnd], AEM_GETMODE, 0, 0
        mov     [.oldmode], eax

        mov     [.si.cbSize], sizeof.SCROLLINFO
        mov     [.si.fMask], SIF_POS
        lea     eax, [.si]
        invoke  GetScrollInfo, [.hwnd], SB_VERT, eax

        invoke  SendMessageW, [.hwnd], AEM_SETMODE, 0, 0    ; because of the vertical selection.

        lea     eax, [.oldpos]
        invoke  SendMessageW, [.hwnd], AEM_GETPOS, eax, 0
        sub     [.oldpos.caretLine], ebx
        sub     [.oldpos.selectionLine], ebx
        sub     [.si.nPos], ebx

        mov     [.pos.caretPosition], 1
        lea     eax, [ebx+1]
        mov     [.pos.caretLine], eax
        mov     [.pos.selectionPosition], 1
        mov     [.pos.selectionLine], 1

        lea     eax, [.pos]
        invoke  SendMessageW, [.hwnd], AEM_SETPOS, eax, 0

        invoke  SendMessageW, [.hwnd], EM_REPLACESEL, 0, 0
        stdcall UnSelect, [.hwnd]

        invoke  SendMessageW, [.hwnd], EM_REPLACESEL, 0, cFormPrefix
        stdcall UnSelect, [.hwnd]

        stdcall utf8ToWideChar, esi
        push    eax

        invoke  SendMessageW, [.hwnd], EM_REPLACESEL, 0, eax
        stdcall UnSelect, [.hwnd]

        stdcall FreeMem ; from the stack
        stdcall StrDel, esi

        invoke  SendMessageW, [.hwnd], EM_REPLACESEL, 0, cFormSuffix
        stdcall UnSelect, [.hwnd]

        stdcall CountDesignWindows, edi
        add     eax, 2

        add     [.oldpos.caretLine], eax
        add     [.oldpos.selectionLine], eax
        add     [.si.nPos], eax

        invoke  SendMessageW, [.hwnd], AEM_READONLY, eax, 0

        invoke  SendMessageW, [.hwnd], AEM_SETMODE, [.oldmode], 0

        lea     eax, [.oldpos]
        invoke  SendMessageW, [.hwnd], AEM_SETPOS, eax, 0

        lea     eax, [.si]
        invoke  SetScrollInfo, [.hwnd], SB_VERT, eax, FALSE

        mov     eax, [.si.nPos]
        shl     eax, 16
        or      eax, SB_THUMBTRACK
        invoke  SendMessageW, [.hwnd], WM_VSCROLL, eax, 0

        stdcall SourceEditProc, [.hwnd], [.wmsg], [.wparam], [.lparam]
        return


.errortext:
        xor     eax, eax
        inc     eax
        clc
        return


;-----------------------------------------------------------------------
oncase _CEM_CHANGENOTIFY
        invoke  GetParent, [.hwnd]
        invoke  SendMessageW, eax, EHM_FILECHANGED, edi, 0
        clc
        return


;-----------------------------------------------------------------------
oncase _CEM_FOCUSFILE

        invoke  GetParent, [.hwnd]
        invoke  SendMessageW, eax, EHM_FOCUSWINDOW, [.hwnd], 0
        clc
        return


;-----------------------------------------------------------------------
oncase _CEM_CANACTION
  locals
    .aepos AEPOS
  endl
        mov     eax, [.lparam]
        cmp     eax, WM_CUT
        je      .checkcopycut
        cmp     eax, WM_COPY
        je      .checkcopycut
        cmp     eax, WM_CLEAR
        je      .checkcopycut
        cmp     eax, WM_UNDO
        je      .checkundo
        cmp     eax, EM_UNDO
        je      .checkundo
        cmp     eax, WM_PASTE
        je      .checkpaste
        xor     eax, eax
        clc
        return

.checkcopycut:

        invoke  GetPropW, [.hwnd], [propVisualMode]
        test    eax, eax
        jz      .checksource

        invoke  GetPropW, [.hwnd], [propWinTemplate]
        test    eax, eax
        jz      .exitcopycheck

        stdcall GetSelectionList, eax
        test    eax, eax
        jz      .exitcopycheck

        mov     eax, [eax+TArray.count]

.exitcopycheck:
        clc
        return


.checksource:
        lea     esi, [.aepos]
        invoke  SendMessageW, [.hwnd], AEM_GETPOS, esi, 0
        mov     eax, [esi+AEPOS.caretPosition]
        mov     ecx, [esi+AEPOS.caretLine]
        cmp     [esi+AEPOS.selectionPosition], eax
        jne     .can_copy
        cmp     [esi+AEPOS.selectionLine], ecx
        jne     .can_copy

        xor     eax, eax
        clc
        return

.can_copy:
        xor     eax, eax
        inc     eax
        clc
        return

.checkundo:
        invoke  SendMessageW, [.hwnd], EM_CANUNDO, 0, 0
        clc
        return

.checkpaste:
        invoke  IsClipboardFormatAvailable, CF_TEXT
        clc
        return


;-----------------------------------------------------------------------
oncase _CEM_EDITACTION

        invoke  GetPropW, [.hwnd], [propVisualMode]
        test    eax, eax
        jnz     .formmode

        invoke  SendMessageW, [.hwnd], [.lparam], 0, 0
        clc
        return

;-------------------------------------
; Common actions for form edit mode
;-------------------------------------
.formmode:
        cmp     [.lparam], WM_COPY
        je      .copycontrol

        cmp     [.lparam], WM_CUT
        je      .cutcontrol

        cmp     [.lparam], WM_CLEAR
        je      .delcontrol

        cmp     [.lparam], WM_PASTE
        je      .pastecontrol

        clc
        return

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.pastecontrol:
  locals
    .hmem dd ?
    .ptrTarget dd ?
  endl
        invoke  IsClipboardFormatAvailable, CF_TEXT
        test    eax, eax
        jz      .endpaste

        invoke  OpenClipboard, NULL

        invoke  GetClipboardData, CF_UNICODETEXT
        test    eax, eax
        jz      .closepastecb

        mov     [.hmem], eax
        invoke  GlobalLock, eax
        push    eax

        stdcall WideCharToUtf8, eax
        mov     esi, eax

        invoke  GlobalUnlock, [.hmem]

        mov     [.hmem], esi
        stdcall StrPtr, esi
        mov     esi, eax

        invoke  GetPropW, [.hwnd], [propWinTemplate]
        test    eax, eax
        jz      .endpaste

        mov     edi, eax

; search for paste target
        stdcall GetSelectionList, edi
        mov     ecx, [eax+TArray.count]
        jecxz   .compileloop

        mov     edi, [eax+TArray.array]


; Compile windows from clipboard...
.compileloop:
        stdcall CompileSourceTemplate, esi
        test    eax, eax
        jz      .endcompileloop

        mov     esi, edx
        mov     ebx, eax

        lea     ecx, [edi+TWinTemplateDT.children]
        stdcall AddArrayItems, [edi+TWinTemplateDT.children], 1
        mov     [edi+TWinTemplateDT.children], edx
        mov     [eax], ebx
        mov     [ebx+TWinTemplateDT.parent], edi

; Check for coordinates to be inside client area of the target

        mov     cx, [ebx+TWinTemplateDT.left]
        mov     dx, [ebx+TWinTemplateDT.top]

.adjustx:
        cmp     cx, [edi+TWinTemplateDT.width]
        jb      .adjusty
        sub     cx, [edi+TWinTemplateDT.width]
        jmp     .adjustx

.adjusty:
        cmp     dx, [edi+TWinTemplateDT.height]
        jb      .xyok
        sub     dx, [edi+TWinTemplateDT.height]
        jmp     .adjusty

; Creates windows instances...
.xyok:
        mov     [ebx+TWinTemplateDT.left], cx
        mov     [ebx+TWinTemplateDT.top], dx
        stdcall CreateDesignWindow, ebx
        invoke  SendMessageW, [.hwnd], AEM_SETMODIFIED, TRUE, 0
        jmp     .compileloop

.endcompileloop:

        stdcall StrDel, [.hmem]

.closepastecb:
        invoke  CloseClipboard

.endpaste:
        clc
        return

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.cutcontrol:
        invoke  SendMessageW, [.hwnd], _CEM_EDITACTION, 0, WM_COPY

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.delcontrol:
        invoke  GetPropW, [.hwnd], [propWinTemplate]

        test    eax, eax
        jz      .exitdel

        push    eax
        stdcall GetSelectionList, eax

        mov     ebx, [eax+TArray.count]
        lea     esi, [eax+TArray.array]

.delloop:
        dec     ebx
        js      .enddel

        stdcall DestroyDesignWindow, [esi+4*ebx], TRUE
        jmp     .delloop

.enddel:
        pop     eax
        stdcall GetSizer
        invoke  SendMessageW, eax, SZM_UNSELECTALL, 0, 0
        invoke  SendMessageW, [.hwnd], AEM_SETMODIFIED, TRUE, 0

.exitdel:
        clc
        return

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.copycontrol:
        stdcall StrNew
        mov     ebx, eax

        invoke  GetPropW, [.hwnd], [propWinTemplate]
        test    eax, eax
        jz      .endcopy

        stdcall GetSelectionList, eax

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

.copyselected:
        dec     edi
        js      .endcopyloop

        stdcall CreateSourceTemplate, [esi]
        stdcall StrCat, ebx, eax
        stdcall StrDel, eax

        add     esi, 4
        jmp     .copyselected

.endcopyloop:
        stdcall StrLen, ebx
        test    eax, eax
        jz      .endcopy

        lea     esi, [eax+1]

        invoke  OpenClipboard, NULL
        test    eax, eax
        jz      .endcopy

        invoke  EmptyClipboard

        invoke  GlobalAlloc, GHND or GMEM_DDESHARE, esi
        test    eax, eax
        jz      .closecb

        mov     [.hmem], eax

        invoke  GlobalLock, eax
        mov     edi, eax

        mov     ecx, esi
        stdcall StrPtr, ebx
        mov     esi, eax
        rep movsb
        invoke  GlobalUnlock, [.hmem]

        invoke  SetClipboardData, CF_TEXT, [.hmem]

.closecb:
        invoke  CloseClipboard

.endcopy:
        stdcall StrDel, ebx
        clc
        return


;-----------------------------------------------------------------------
oncase _CEM_GETMODIFIED
        invoke   SendMessageW, [.hwnd], AEM_GETMODIFIED, 0, 0
        clc
        return

;-----------------------------------------------------------------------
oncase _CEM_SETMODIFIED
        invoke  SendMessageW, [.hwnd], AEM_SETMODIFIED, [.wparam], [.lparam]
        clc
        return


;-----------------------------------------------------------------------
oncase _CEM_GETFILE
        mov     eax, edi
        clc
        return


;-----------------------------------------------------------------------
oncase _CEM_GETASMEDIT
        mov     eax, [.hwnd]
        clc
        return

;-----------------------------------------------------------------------
oncase WM_DESTROY

        invoke  GetPropW, [.hwnd], [propWinTemplate]
        stdcall DestroyDesignWindow, eax, TRUE
        stdcall SourceEditProc, [.hwnd], [.wmsg], [.wparam], [.lparam]
        return


        enddispatch
endp




;------------------------------------------------------------------------
; Several callback procedures for EnumSelections procedure "formsDT.asm"
;------------------------------------------------------------------------
proc CopySelectedVisual, .dummy, .ptrList, .hString
begin
        push    esi edi ebx

        mov     esi, [.ptrList]
        mov     ebx, [esi+TList.Count]
        mov     esi, [esi+TList.ptrItems]

.loop:
        dec     ebx
        js      .endloop

        stdcall CreateSourceTemplate, [esi]
        stdcall StrCat, [.hString], eax
        stdcall StrDel, eax

        add     esi, 4
        jmp     .loop

.endloop:
        pop     ebx edi esi
        return
endp



proc UnselectAll, .ptrWinTemplateDT
begin
        mov     eax, [.ptrWinTemplateDT]
        stdcall GetSizer
        invoke  SendMessageA, eax, SZM_UNSELECTALL, 0, 0
        return
endp





proc UnSelect, .hAsmEdit
.pos AEPOS
begin
        pushad

        lea     esi, [.pos]

        invoke  SendMessageW, [.hAsmEdit], AEM_GETPOS, esi, 0

;        OutputValue "Caret pos: ", [.pos.caretPosition], 10, -1
;        OutputValue "Caret line: ", [.pos.caretLine], 10, -1
;        OutputValue "Selection pos: ", [.pos.selectionPosition], 10, -1
;        OutputValue "Selection line: ", [.pos.selectionLine], 10, -1

        mov     eax, [.pos.selectionPosition]
        mov     ecx, [.pos.selectionLine]
        mov     [.pos.caretPosition], eax
        mov     [.pos.caretLine], ecx

        invoke  SendMessageW, [.hAsmEdit], AEM_SETPOS, esi, 0

        popad
        return
endp