; _______________________________________________________________________________________
;|                                                                                       |
;| ..::FreshLib::..  Free, open source. Licensed under "BSD 2-clause" license."          |
;|_______________________________________________________________________________________|
;
;  Description: Objects template engine
;
;  Target OS: Any
;
;  Dependencies: objects.asm
;
;  Notes:
;_________________________________________________________________________________________
module "Templates library"

tfChild  = 0
tfParent = 1
tfEnd    = 2


struct TObjTemplate
  .flags     dd  ?         ; tfParent; tfEnd.
  .size      dd  ?         ; size of the instance structure.
  .vtable    dd  ?         ; pointer to the virtual methods table.
  .paramsize dd  ?
  .ptrVar    dd  ?
  .params:
ends


macro ObjTemplate  flags, class, name, [idparam] {
common
local ..paramsize, ..prms, ..here

   if ~defined used.#class | defined ..here
     used.#class = 1
     ..here = 1
   end if

      dd  flags
      dd  sizeof.#class
      dd  vtables.#class
      dd  ..paramsize
      dd  name

..prms:

forward
local ..value, ..ofs, ..valid

  ..valid equ FALSE
  match  id == param, idparam \{
    ..ofs dd  class\#.\#id\#.#set
          dd  ..value
    ..valid EQU TRUE
  \}

  match =FALSE, ..valid \{
    error Invalid parameter definition in template.
  \}

common
      dd  -1

forward

    match  id == param, idparam \{
      if param eqtype 2
        ..value = param
      else
        if param eqtype [2]
           match =[par=], param \\{
           ..value = par
        \\}
          store byte $fe at ..ofs+3
        else
          ..value db param, 0
        end if
      end if
    \}

common
local ..here

    if ~defined name | defined ..here
      name dd ?
      ..here = 1
    end if
  ..paramsize = $ - ..prms
}


; returns the last created window in ebx.
proc CreateFromTemplate, .ptrTemplate, .parent
begin
        push    esi

        mov     esi, [.ptrTemplate]
        stdcall _DoCreateFromTemplate, [.parent]

        pop     esi
        return
endp


proc _DoCreateFromTemplate, .parent
begin
        push    eax ecx edx edi

.createloop:
        stdcall GetMem, [esi+TObjTemplate.size]
        mov     ebx, eax
        mov     edi, [esi+TObjTemplate.vtable]
        mov     [ebx], edi

        exec    ebx, TWindow:Create, [.parent]

        lea     ecx, [esi+TObjTemplate.params]

.paramloop:
        cmp     dword [ecx], -1
        je      .paramsok

        mov     eax, [ecx]
        bswap   eax

        mov     edx, [ecx+4]            ; value

        cmp     al, $fe                 ; Is it indirect?
        jne     @f
        mov     edx, [edx]              ; the value is an address of a variable.
@@:
        bswap   eax

        test    eax, $00ff0000
        movzx   eax, ax                 ; not changing flags!
        jnz     .method

        mov     [ebx+eax], edx
        jmp     .param_set

.method:
        stdcall dword [edi+4*eax+8], ebx, edx

.param_set:
        add     ecx, 8
        jmp     .paramloop

.paramsok:
        mov     eax, [esi+TObjTemplate.ptrVar]
        test    eax, eax
        jz      .var_ok

        mov     [eax], ebx      ; returned pointer/handle to the object.
        set     ebx, TObject:ptrVar, eax

.var_ok:
        get     eax, ebx, TObject:OnCreate
        test    eax, eax
        jz      .gonext

; execute user OnCreate event.

        pushad
        stdcall eax, ebx
        popad

.gonext:
        mov     edx, [esi+TObjTemplate.flags]

        mov     eax, sizeof.TObjTemplate
        add     eax, [esi+TObjTemplate.paramsize]
        add     esi, eax

        test    edx, tfParent
        jz      .childrenok

        push    ebx
        stdcall _DoCreateFromTemplate, ebx
        pop     ebx

.childrenok:
        test    edx, tfEnd
        jz      .createloop

.exit:
        pop     edi edx ecx eax
        return
endp


endmodule