; _______________________________________________________________________________________
;|                                                                                       |
;| ..::FreshLib::..  Free, open source. Licensed under "BSD 2-clause" license."          |
;|_______________________________________________________________________________________|
;
;  Description: Actions management library.
;
;  Target OS: Any
;
;  Dependencies:
;
;  Notes: "Action" is set of executable code, combined with user interface attributes -
;         caption, accelerator keys, enable/disable status flag etc.
;         Different UI elements, such as buttons, menu items etc. can be attached to
;         the action object and to use its attributes. When the programmer changes
;         something in the action, all UI elements are updated automatically.
;_________________________________________________________________________________________

module "TAction"

Ctrl = maskCtrl
Alt = maskAlt
Shift = maskShift


fkScancode = $80000000

struct TFastKey
 .flags  dd ?
 .key    dd ?
ends


object TAction, TObject

  ._caption    dd ?
  ._hint_text  dd ?
  ._icon_index dd ?
  ._enabled    dd ?
  ._checked    dd ?

  ._accel      TFastKey

  ._on_execute dd ?
  ._on_idle    dd ?

  ._ctrl_list  dd ?

  ._icon_cache_gray  dd ?
  ._icon_cache       dd ?

  param .Caption,   ._caption,    .SetCaption
  param .HintText,  ._hint_text,  .SetHintText
  param .IconIndex, ._icon_index, .SetIconIndex
  param .Enabled,   ._enabled,    .SetEnabled
  param .Checked,   ._checked,    .SetChecked
  param .AccelStr,  .GetAccelStr, NONE
  param .Icon, .GetIcon, NONE

  param .OnExecute, ._on_execute, ._on_execute
  param .OnIdle,    ._on_idle,    ._on_idle

  method .GetIcon
  method .GetAccelStr

  method .SetParent, .value

  method .SetCaption, .value
  method .SetHintText, .value
  method .SetIconIndex, .value
  method .SetEnabled, .value
  method .SetChecked, .value

  method .UpdateControls

  method .SetAccelerator, .flags, .key

  method .Execute, .fromCtrl
  method .Attach,  .ctrl
  method .Detach,  .ctrl

  method .Create, .parent
  method .Destroy

  method .__clear_cache

endobj



interface TAction.OnExecute, .Action, .Ctrl



method TAction.Create
begin
        inherited [.parent]

        mov     eax, [.self]
        mov     [eax+TAction._enabled], 1
        return
endp




method TAction.Destroy
begin
        pushad

        mov     esi, [.self]
        exec    esi, TAction:__clear_cache

        mov     edi, [esi+TAction._ctrl_list]
        test    edi, edi
        je      .finish

        mov     ecx, [edi+TArray.count]

.loop:
        dec     ecx
        js      .end_loop

        set     [edi+TArray.array+4*ecx], TWindow:Action, 0
        jmp     .loop

.end_loop:
        stdcall FreeMem, edi


.finish:
        popad
        inherited
        return
endp



method TAction.SetParent
begin
        inherited [.value]
        exec      [.self], TAction:UpdateControls
        return
endp



method TAction.Execute
begin
        pushad

        mov     esi, [.self]

        cmp     [esi+TAction._enabled], 0
        je      .finish

        mov     edi, [esi+TAction._on_execute]
        test    edi, edi
        jz      .finish

        stdcall edi, esi, [.fromCtrl]

.finish:
        popad
        return
endp




method TAction.Attach
begin
        pushad

        mov     esi, [.self]
        mov     edx, [esi+TAction._ctrl_list]
        test    edx, edx
        jnz     @f

        stdcall CreateArray, 4
        mov     edx, eax
@@:

        stdcall AddArrayItems, edx, 1
        mov     ecx, [.ctrl]
        mov     [eax], ecx

        mov     [esi+TAction._ctrl_list], edx

        popad
        return
endp




method TAction.Detach
begin
        pushad

        mov     esi, [.self]
        mov     edx, [esi+TAction._ctrl_list]
        test    edx, edx
        jz      .finish

        stdcall ListIndexOf, edx, [.ctrl]
        jc      .finish                         ; not found

        stdcall DeleteArrayItems, edx, eax, 1

        cmp     [edx+TArray.count], 0
        jne     @f

        stdcall FreeMem, edx
        xor     edx, edx

@@:
        mov     [esi+TAction._ctrl_list], edx

.finish:
        popad
        return
endp




method TAction.GetIcon
.list dd ?
begin
        pushad
        mov     esi, [.self]

        mov     edi, [esi+TAction._enabled]
        and     edi, 1

        mov     eax, [esi+TAction._icon_cache_gray+4*edi]
        test    eax, eax
        jnz     .finish

        mov     edx, [esi+TAction._icon_index]
        test    edx, edx
        js      .finish         ; return 0

        get     [.list], esi, TAction:Parent
        get     ecx, [.list], TActionList:IconSize

        stdcall CreateImage, ecx, ecx
        mov     [esi+TAction._icon_cache_gray+4*edi], eax

        imul    edx, ecx                                ; x coordinate.

        get     ebx, [.list], TActionList:ImgIcons
        test    ebx, ebx
        jz      .finish

        stdcall CopyImageRect, eax, 0, 0, ebx, edx, 0, ecx, ecx
        test    edi, edi
        jnz     .finish

        stdcall FilterDisabled, eax, FALSE

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


method TAction.GetAccelStr
begin
        mov     eax, [.self]
        lea     eax, [eax+TAction._accel]
        stdcall AcceleratorToStr, eax
        return
endp



method TAction.__clear_cache
begin
        push    eax edx

        mov     edx, [.self]

        xor     eax, eax
        xchg    eax, [edx+TAction._icon_cache]
        test    eax, eax
        jz      .cache_ok1

        stdcall DestroyImage, eax

.cache_ok1:
        xor     eax, eax
        xchg    eax, [edx+TAction._icon_cache_gray]
        test    eax, eax
        jz      .cache_ok2

        stdcall DestroyImage, eax

.cache_ok2:

        pop     edx eax
        return
endp



method TAction.UpdateControls
begin
        push    eax ecx edx

        mov     edx, [.self]

        exec    edx, TAction:__clear_cache

        mov     edx, [edx+TAction._ctrl_list]
        test    edx, edx
        jz      .finish

        mov     ecx, [edx+TArray.count]

.loop:
        dec     ecx
        js      .finish

        exec    [edx+TArray.array+4*ecx], TWindow:UpdateAction, [.self]
        jmp     .loop

.finish:
        pop     edx ecx eax
        return
endp




method TAction.SetCaption      ;, .value
begin
        pushad
        mov     esi, [.self]
        mov     eax, [.value]
        cmp     eax, [esi+TAction._caption]
        je      .finish

        mov     [esi+TAction._caption], eax
        exec    esi, TAction:UpdateControls

.finish:
        popad
        return
endp



method TAction.SetHintText     ;, .value
begin
        pushad
        mov     esi, [.self]
        mov     eax, [.value]
        cmp     eax, [esi+TAction._hint_text]
        je      .finish

        mov     [esi+TAction._hint_text], eax
        exec    esi, TAction:UpdateControls

.finish:
        popad
        return
endp



method TAction.SetIconIndex    ;, .value
begin
        pushad
        mov     esi, [.self]
        mov     eax, [.value]
        cmp     eax, [esi+TAction._icon_index]
        je      .finish

        mov     [esi+TAction._icon_index], eax
        exec    esi, TAction:UpdateControls

.finish:
        popad
        return
endp



method TAction.SetEnabled      ;, .value
begin
        pushad
        mov     esi, [.self]
        mov     eax, [.value]
        cmp     eax, [esi+TAction._enabled]
        je      .finish

        mov     [esi+TAction._enabled], eax
        exec    esi, TAction:UpdateControls

.finish:
        popad
        return
endp



method TAction.SetChecked      ;, .value
begin
        pushad
        mov     esi, [.self]
        mov     eax, [.value]
        cmp     eax, [esi+TAction._checked]
        je      .finish

        mov     [esi+TAction._checked], eax

        exec    esi, TAction:UpdateControls

.finish:
        popad
        return
endp



method TAction.SetAccelerator
begin
        pushad

        mov     esi, [.self]

        mov     eax, [.flags]
        mov     ecx, [.key]

        test    eax, fkScancode
        jz      @f

        or      ecx, fkScancode

@@:
        and     eax, not fkScancode
        mov     [esi+TAction._accel.flags], eax
        mov     [esi+TAction._accel.key], ecx

        exec    esi, TAction:UpdateControls

        popad
        return
endp


endmodule