; _______________________________________________________________________________________
;|                                                                                       |
;| ..::FreshLib::..  Free, open source. Licensed under "BSD 2-clause" license."          |
;|_______________________________________________________________________________________|
;
;  Description: TObject object class.
;
;  Target OS: Any
;
;  Dependencies:
;
;  Notes: TObject is the root member of FreshLib objects tree.
;_________________________________________________________________________________________
module "TObject library"




object TObject
; fields
  if options.Threads
    ._mxAccess  TMutex  ; access mutex. Procedures from objects.asm will use it to ensure thread safety.
  end if

  ._OnCreate  dd ?
  ._OnDestroy dd ?
  ._ptrVar    dd ?

  .__Parent       dd ?
  .__pChildren    dd ?   ; pointer to TArray of pointers to children windows.


; parameters

  param .Parent, .__Parent, .SetParent
  param .Children, .__pChildren, NONE

  param  .OnCreate, ._OnCreate, ._OnCreate
  param  .OnDestroy, ._OnDestroy, ._OnDestroy
  param  .ptrVar, ._ptrVar, ._ptrVar

; methods

  method .Create, .parent
  method .Destroy

  method .SetParent, .value

  method .AddChild, .objchild
  method .RemoveChild, .objchild
endobj



interface TObject.OnCreate, .self
interface TObject.OnDestroy, .self





method TObject.Create
begin
if defined options.Threads & options.Threads
        push    eax
        mov     eax, [.self]
        lea     eax, [eax+TObject._mxAccess]
        stdcall MutexCreate, 0, eax
        stdcall MutexRelease, eax
        pop     eax
end if
        set     [.self], TWindow:Parent, [.parent]
        return
endp




method TObject.Destroy
begin
        pushad

        mov     esi, [.self]

        get     ecx, esi, TObject:OnDestroy
        jecxz   .event_ok

        push    esi
        stdcall dword ecx, [.self]
        pop     esi

.event_ok:
        get     ecx, esi, TObject:ptrVar
        jecxz   .varok
        mov     dword [ecx], 0
.varok:

; destroy all children
        get     ebx, esi, TWindow:Children
        test    ebx, ebx
        jz      .end_children

        mov     ecx, [ebx+TArray.count]

.loop:
        dec     ecx
        js      .end_children

        destroy [ebx+TArray.array+4*ecx]
        jmp     .loop

.end_children:

if defined options.Threads & options.Threads
        lea     ecx, [esi+TObject._mxAccess]
        stdcall MutexDestroy, ecx
end if
        popad
        return
endp





;_________________________________________________________________________________________



method TObject.AddChild
begin
        pushad

        mov     esi, [.self]
        mov     ebx, [.objchild]

        istype  ebx, TObject
        jne     .not_window

        mov     edx, [esi+TObject.__pChildren]
        test    edx, edx
        jnz     .array_ok

        stdcall CreateArray, 4
        mov     edx, eax

.array_ok:

        stdcall AddArrayItems, edx, 1
        mov     [eax], ebx
        mov     [esi+TObject.__pChildren], edx

        clc
        popad
        return


.not_window:
        stc
        popad
        return
endp


;_________________________________________________________________________________________


;----------------------------------------------------------------------
; Returns:
;   CF = 1 - if the object specified was not found as a window child.
;   CF = 0 - the child was removed from the list of childrens.
;----------------------------------------------------------------------

method TObject.RemoveChild
begin
        push    edx esi

        mov     esi, [.self]
        mov     edx, [esi+TObject.__pChildren]

        stdcall ListIndexOf, edx, [.objchild]
        jc      .finish

        stdcall DeleteArrayItems, edx, eax, 1

        cmp     [edx+TArray.count], 0
        jne     .store

        stdcall FreeMem, edx
        xor     edx, edx

.store:
        mov     [esi+TObject.__pChildren], edx
        clc

.finish:
        pop     esi edx
        return
endp



;_________________________________________________________________________________________



method TObject.SetParent
begin
        pushad

        mov     esi, [.self]
        mov     edi, [.value]
        cmp     edi, [esi+TObject.__Parent]             ; if the parent is already set to the same value, ignore.
        je      .finish

        cmp     [esi+TWindow.__Parent], 0
        je      .parent_ok

        exec    [esi+TObject.__Parent], TObject:RemoveChild, esi        ; remove the window from the old parent.
        mov     [esi+TObject.__Parent], edi                             ; store the new parent.

.parent_ok:
        test    edi, edi
        jz      .finish

        exec    edi, TObject:AddChild, esi

.finish:
        mov     [esi+TObject.__Parent], edi
        popad
        return
endp



endmodule