; _______________________________________________________________________________________
;|                                                                                       |
;| ..::FreshLib::..  Free, open source. Licensed under "BSD 2-clause" license."          |
;|_______________________________________________________________________________________|
;
;  Description: Main procedure of GUI application library.
;
;  Target OS: Any
;
;  Dependencies:
;
;  Notes: Organize the main message/event loop needed by every GUI engine.
;         This file contains only OS independent part and includes OS dependent files.
;_________________________________________________________________________________________
module "Main library"

uglobal
  var pApplication = ?

  var __LastPointedWindow = ?
  var __FocusedWindow = ?
  var __MouseTarget = ?

  var __ActiveMenu = ?
endg


;_________________________________________________________________________________________
;
; Process all the events queued from the system and exits.
; Arguments: none
; Returns: CF = 1 if the termination event has been received.
;_________________________________________________________________________________________

interface ProcessSystemEvents




;_________________________________________________________________________________________
;
; Waits for system events to arive.
; During the wait, the application
; does not use CPU resources.
;_________________________________________________________________________________________

interface WaitForSystemEvent





proc Run
begin
.mainloop:
        stdcall ProcessSystemEvents
        jc      .terminate

        mov     eax, [pApplication]
        test    eax, eax
        jz      .eventok

        get     ecx, eax, TApplication:OnIdle
        jecxz   .eventok

        stdcall ecx, eax

.eventok:
        stdcall WaitForSystemEvent
        jmp     .mainloop

.terminate:
        DebugMsg "Terminate GUI application!"
        return
endp



proc ServeMenuMouseMove, .window, .x, .y, .kbdState
begin
        cmp     [__ActiveMenu], 0
        jne     .serve_menu

        clc
        return

.serve_menu:
        pushad

        stdcall _ClientToScreen, [.window], [.x], [.y]
        exec    [__ActiveMenu], TWindow:EventMouseMove, ecx, edx, [.kbdState]

        popad
        stc
        return
endp



proc ServeMenuButtonPress, .window, .button, .kbdState, .x, .y
begin
        cmp     [__ActiveMenu], 0
        jne     .serve_menu

        clc
        return

.serve_menu:
        pushad

        stdcall _ClientToScreen, [.window], [.x], [.y]
        exec    [__ActiveMenu], TWindow:EventButtonPress, [.button], [.kbdState], ecx, edx

        popad
        stc
        return
endp



proc ShowModal, .pForm, .pParent
.prev dd ?
begin
        push    ecx edx

        mov     ecx, [.pParent]
        mov     edx, [.pForm]

        set     edx, TForm:Visible, TRUE

        jecxz   @f
        stdcall _SetModalTowards, [edx+TForm.handle], [ecx+TWindow.handle]
@@:

        jecxz   @f
        set     ecx, TWindow:Enabled, FALSE
@@:

        set     edx, TForm:ModalResult, 0

        get     eax, edx, TForm:OnClose
        mov     [.prev], eax

        set     edx, TForm:OnClose, __ModalOnClose

.modal_loop:
        stdcall ProcessSystemEvents
        jc      .exit_modal

        get     eax, edx, TForm:ModalResult
        test    eax, eax
        jnz     .exit_modal

        get     eax, edx, TWindow:Visible
        test    eax, eax
        jz      .exit_modal

.vis_ok:
        stdcall WaitForSystemEvent
        jmp     .modal_loop

.exit_modal:
        jecxz   @f
        set     ecx, TWindow:Enabled, TRUE
@@:

        set     edx, TForm:OnClose, [.prev]

        jecxz   @f
        stdcall _FinalizeModal, [edx+TForm.handle], [ecx+TWindow.handle]
@@:

        set     edx, TForm:Visible, FALSE
        get     eax, edx, TForm:ModalResult
        pop     edx ecx
        return
endp


; prevent destroy of the form from the close button or Alt+F4
proc __ModalOnClose, .self, .reason
begin
        set     [.self], TForm:ModalResult, mrCancel
        stc
        return
endp





proc __GetRelativeXY, .window, .x, .y
begin
        push    eax esi

        mov     ecx, [.x]
        mov     edx, [.y]
        mov     esi, [.window]

.loop:
        get     eax, esi, TWindow:Parent
        test    eax, eax
        jz      .finish

        sub     ecx, [esi+TWindow._x]
        sub     edx, [esi+TWindow._y]

        mov     esi, eax
        jmp     .loop

.finish:
        pop     esi eax
        return
endp



proc __SearchWindowToFocus, .pWindow
begin
        pushad
        mov     esi, [.pWindow]

        get     eax, esi, TWindow:Enabled
        test    eax, eax
        jz      .no

        get     eax, esi, TWindow:Visible
        test    eax, eax
        jz      .no

        get     eax, esi, TWindow:WantFocus
        test    eax, eax
        jz      .children

        mov     [esp+4*regEAX], esi
        popad
        return


.children:
        get     edi, esi, TWindow:Children
        test    edi, edi
        jnz     .loopit

.no:
        xor     eax, eax
        mov     [esp+4*regEAX], eax
        popad
        return

.loopit:
        mov     ecx, [edi+TArray.count]
        jecxz   .no

.children_loop:
        dec     ecx
        js      .no

        mov     esi, [edi+TArray.array+4*ecx]

        istype  esi, TWindow
        jne     .children_loop

        stdcall __SearchWindowToFocus, esi
        test    eax, eax
        jz      .children_loop

        mov     [esp+4*regEAX], eax
        popad
        return
endp




include '%TargetOS%/Main.asm'

endmodule