; ***************************************************************************
; copyright   : (C) 2025 by Martin Preuss
; email       : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome".                              *
; * Please see toplevel file COPYING of that project for license details.   *
; ***************************************************************************

#ifndef AQHOME_AVR_MODS_GUI_DIALOG_ASM
#define AQHOME_AVR_MODS_GUI_DIALOG_ASM



; ***************************************************************************
; defines

.equ DIALOG_MAX_ACTIVE      = 8

.equ DIALOG_OFFS_HANDLER_LO = 0
.equ DIALOG_OFFS_HANDLER_HI = 1
.equ DIALOG_OFFS_OPTIONS    = 2
.equ DIALOG_OFFS_COUNTER    = 3
.equ DIALOG_SIZE            = 4


.equ DIALOG_OPT_ACTIVE_BIT  = 7


.equ DIALOG_FN_INIT  = 0
.equ DIALOG_FN_FINI  = 1
.equ DIALOG_FN_SHOW  = 2
.equ DIALOG_FN_HIDE  = 3
.equ DIALOG_FN_TOUCH = 4
.equ DIALOG_FN_TIMER = 5



; ***************************************************************************
; data

.dseg

dialogCurrent:  .byte 2
dialogStack:    .byte DIALOG_MAX_ACTIVE*2
dialogStackPos: .byte 1

dialogWindow:   .byte WIN_SIZE



; ***************************************************************************
; code

.cseg


; ---------------------------------------------------------------------------
; @routine GraphApp_Init @global
;

DialogMgr_Init:
  clr r16
  sts dialogStackPos, r16
  sts dialogCurrent, r16
  sts dialogCurrent+1, r16
  
  ldi yl, LOW(dialogWindow)
  ldi yh, HIGH(dialogWindow)
  bigcall TitleWindow_Init

  ldi zl, LOW(STYLE_WIN_FONT*2)
  ldi zh, HIGH(STYLE_WIN_FONT*2)
  std Y+WIN_OFFS_FONT_LO, zl
  std Y+WIN_OFFS_FONT_HI, zh
  
  bigcall TitleWindow_SetFullSize  
  bigcall TitleWindow_SetStyleColors

  bigcall Window_Clear
  ret
; @end



; ---------------------------------------------------------------------------
; @routine DialogMgr_Every100ms @global
;
; Handle display touch events
; Send timer event to every app in the stack (started with last added app).

DialogMgr_Every100ms:
  ; check for touch input changes
  rcall Display_InputGetState    ; r16=flags, r5:r4=x, r7:r6=y
  mov r17, r16
  andi r17, (1<<DISPLAY_IFLAGS_CHGCOORD_BIT) | (1<<DISPLAY_IFLAGS_CHGPRESS_BIT)
  breq DialogMgr_Every100ms_sendTimer
  mov r18, r16
  ldi r23, DIALOG_FN_TOUCH
  rcall DialogMgr_CallCurrentHandler
DialogMgr_Every100ms_sendTimer:
  ; send timer event to all dialogs in stack
  ldi xl, LOW(dialogStack)
  ldi xh, HIGH(dialogStack)

  lds r16, dialogStackPos
  mov r17, r16
  add r16, r16
  add xl, r16
  adc xh, r16
  sub xh, r16

DialogMgr_Every100ms_loop:
    tst r17
    breq DialogMgr_Every100ms_ret
    ld yh, -X
    ld yl, -X
    push xl
      push xh
        push r17
          ldi r23, DIALOG_FN_TIMER
          rcall DialogMgr_CallHandler
        pop r17
      pop xh
    pop xl
    dec r17
  rjmp DialogMgr_Every100ms_loop
DialogMgr_Every100ms_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine DialogMgr_CallHandler @global
;
; @param Y   pointer to app data
; @param R23 number of function to call
; @clobbers R16, R17, R22, X (any)

DialogMgr_CallHandler:
  tst yl
  brne DialogMgr_CallHandler_go
  tst yh
  breq DialogMgr_CallHandler_ret
DialogMgr_CallHandler_go:
  ldi xl, LOW(dialogWindow)
  ldi xh, HIGH(dialogWindow)
  ldd r16, Y+DIALOG_OFFS_HANDLER_LO
  ldd r17, Y+DIALOG_OFFS_HANDLER_HI
  mov r22, r16
  and r22, r17
  breq DialogMgr_CallHandler_ret
  push r16
  push r17
DialogMgr_CallHandler_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine DialogMgr_CallCurrentHandler @global
;
; @param X   pointer to window
; @param R23 number of function to call
; @clobbers R22 (any)

DialogMgr_CallCurrentHandler:
  lds yl, dialogCurrent
  lds yh, dialogCurrent+1
  rjmp DialogMgr_CallHandler
; @end



; ---------------------------------------------------------------------------
; @routine DialogMgr_PushDialog @global
;
; @param Y   pointer to app data
;
DialogMgr_PushDialog:
  lds r16, dialogStackPos
  cpi r16, DIALOG_MAX_ACTIVE
  brcc DialogMgr_PushDialog_ret
  
  tst r16
  brne DialogMgr_PushDialog_push
  ; deactivate previous app
  push yl
    push yh
      lds yl, dialogCurrent
      lds yh, dialogCurrent+1
      ldi r23, DIALOG_FN_HIDE
      rcall DialogMgr_CallHandler
      ldd r17, Y+DIALOG_OFFS_OPTIONS
      cbr r17, (1<<DIALOG_OPT_ACTIVE_BIT)
      std Y+DIALOG_OFFS_OPTIONS, r17
    pop yh
  pop yl

DialogMgr_PushDialog_push:
  lds r16, dialogStackPos
  mov r17, r16
  add r17, r17 ; *2
  push xl
    push xh
      ldi xl, LOW(dialogStack)
      ldi xh, HIGH(dialogStack)
      add xl, r17
      adc xh, r17
      sub xh, r17
      st X+, yl
      st X, yh
    pop xh
  pop xl
  inc r16
  sts dialogStackPos, r16
  sts dialogCurrent, yl
  sts dialogCurrent+1, yh
  ; activate new app
  ldd r17, Y+DIALOG_OFFS_OPTIONS
  ori r17, (1<<DIALOG_OPT_ACTIVE_BIT)
  std Y+DIALOG_OFFS_OPTIONS, r17
  
  ldi r23, DIALOG_FN_SHOW
  rcall DialogMgr_CallHandler
  sec
DialogMgr_PushDialog_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine DialogMgr_PopDialog @global
;
; @return CFLAG set if app popped from stack, cleared otherwise
; @return Y app popped from stack (if CFLAG set)

DialogMgr_PopDialog:
  lds r16, dialogStackPos
  tst r16
  clc
  brne DialogMgr_PopDialog_ret
  ; deactivate previous app
  push yl
    push yh
      lds yl, dialogCurrent
      lds yh, dialogCurrent+1
      ldi r23, DIALOG_FN_HIDE
      rcall DialogMgr_CallHandler
      ldd r17, Y+DIALOG_OFFS_OPTIONS
      cbr r17, (1<<DIALOG_OPT_ACTIVE_BIT)
      std Y+DIALOG_OFFS_OPTIONS, r17
    pop yh
  pop yl

  lds r16, dialogStackPos
  dec r16
  sts dialogStackPos, r16
  brne DialogMgr_PopDialog_pop
  clr r16
  sts dialogCurrent, r16
  sts dialogCurrent+1, r16
  sec
  rjmp DialogMgr_PopDialog_ret
DialogMgr_PopDialog_pop:
  push xl
    push xh
      ldi xl, LOW(dialogStack)
      ldi xh, HIGH(dialogStack)
      add xl, r16
      adc xh, r16
      sub xh, r16
      ld yl, X+
      ld yh, X
      sts dialogCurrent, yl
      sts dialogCurrent+1, yh
    pop xh
  pop xl
  ; activate new active app
  ldd r17, Y+DIALOG_OFFS_OPTIONS
  ori r17, (1<<DIALOG_OPT_ACTIVE_BIT)
  std Y+DIALOG_OFFS_OPTIONS, r17
  ldi r23, DIALOG_FN_SHOW
  rcall DialogMgr_CallHandler
  sec
DialogMgr_PopDialog_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine Dialog_Init @global
;
; @param Y pointer to screen object in SDRAM
; @clobbers R16, R17, X

Dialog_Init:
  mov xl, yl
  mov xh, yh
  ldi r17, DIALOG_SIZE
  clr r16
  bigcall Utils_FillSram      ; (R17, X)
  ret
; @end




#endif ; AQHOME_AVR_MODS_GUI_DIALOG_ASM

