; ***************************************************************************
; 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 AQH_AVR_STATICGUI_WINDOW_ASM
#define AQH_AVR_STATICGUI_WINDOW_ASM



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

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



; ---------------------------------------------------------------------------
; @routine Window_Clear @global
;
; @param Y pointer to screen object in SDRAM
; @clobbers any, !Y

Window_Clear:
  ldd r2, Y+WIN_OFFS_BG_COL_LO  ; background color low
  ldd r3, Y+WIN_OFFS_BG_COL_HI  ; background color high
  ldd r4, Y+WIN_OFFS_X_LO       ; X low
  ldd r5, Y+WIN_OFFS_X_HI       ; X high
  ldd r6, Y+WIN_OFFS_Y_LO       ; Y low
  ldd r7, Y+WIN_OFFS_Y_HI       ; Y high
  ldd r8, Y+WIN_OFFS_WIDTH_LO   ; width low
  ldd r9, Y+WIN_OFFS_WIDTH_HI   ; width high
  ldd r10, Y+WIN_OFFS_HEIGHT_LO ; height low
  ldd r11, Y+WIN_OFFS_HEIGHT_HI ; height high
  bigcall Display_FillRect
  ret
; @end



; ---------------------------------------------------------------------------
; @routine Window_FillRect @global
;
; @param Y pointer to screen object in SDRAM
; @param r3:r2 color
; @param r5:r4   X0
; @param r7:r6   Y0
; @param r9:r8   X1/W
; @param r11:r10 Y1/H
; @clobbers any, !Y

Window_FillRect:
  ldd r16, Y+WIN_OFFS_X_LO  ; make absolute coords
  ldd r17, Y+WIN_OFFS_X_HI
  add r4, r16
  adc r5, r17
  ldd r16, Y+WIN_OFFS_Y_LO
  ldd r17, Y+WIN_OFFS_Y_HI
  add r6, r16
  adc r7, r17
  bigcall Display_FillRect ; directly call graphics function
  ret
; @end



; ---------------------------------------------------------------------------
; @routine Window_DrawTextFlash @global
;
; @param Y pointer to screen object in SDRAM
; @param  R5:R4   X (dest)
; @param  R7:R6   Y (dest)
; @return R5:R4   X pos behind string

; @clobbers any, !Y, !R6, !R7

Window_DrawTextFlash:
  ldd r0, Y+WIN_OFFS_BG_COL_LO
  ldd r1, Y+WIN_OFFS_BG_COL_HI
  ldd r2, Y+WIN_OFFS_FG_COL_LO
  ldd r3, Y+WIN_OFFS_FG_COL_HI

  rjmp Window_DrawColorTextFlash
; @end



; ---------------------------------------------------------------------------
; @routine Window_DrawColorTextFlash @global
;
; @param Y pointer to screen object in SDRAM
; @param  R1:R0   background color
; @param  R3:R2   foreground color
; @param  R5:R4   X (dest)
; @param  R7:R6   Y (dest)
; @return R5:R4   X pos behind string

; @clobbers any, !Y, !R6, !R7

Window_DrawColorTextFlash:
  rcall winCalcAbsPosAndBorders       ; (R18, R19)
Window_DrawColorTextFlash_loop:
    lpm r16, Z
    tst r16
    breq Window_DrawColorTextFlash_loopEnd
    rcall winDrawChar
    brcc Window_DrawColorTextFlash_loopEnd
    adiw zh:zl, 1                     ; next char
  rjmp Window_DrawColorTextFlash_loop
Window_DrawColorTextFlash_loopEnd:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine Window_DrawCharAt @global
;
; @param Y pointer to screen object in SDRAM
; @param  R16     char to write
; @param  R5:R4   X (dest)
; @param  R7:R6   Y (dest)
; @return R5:R4   X pos behind char
; @clobbers any, !Y

Window_DrawCharAt:
  rcall winCalcAbsPosAndBorders

  ldd r0, Y+WIN_OFFS_BG_COL_LO
  ldd r1, Y+WIN_OFFS_BG_COL_HI
  ldd r2, Y+WIN_OFFS_FG_COL_LO
  ldd r3, Y+WIN_OFFS_FG_COL_HI

  rjmp winDrawChar
; @end



; ---------------------------------------------------------------------------
; @routine winCalcAbsPosAndBorders
;
; @param Y pointer to screen object in SDRAM
; @param  R5:R4   X relative to window
; @param  R7:R6   Y relative to window
; @return R9:R8   first X pos right of windows
; @return R5:R4   X relative to screen
; @return R7:R6   Y relative to screen
; @return R9:R8   first X pos right of window (abs)
; @return R11:R10 first Y pos below window (abs)
; @clobbers r18, r19

winCalcAbsPosAndBorders:
  ; calc abs X pos
  ldd r18, Y+WIN_OFFS_X_LO
  ldd r19, Y+WIN_OFFS_X_HI
  add r4, r18                  ; add X of window
  adc r5, r19

  ; calc first X pos behind window
  ldd r8, Y+WIN_OFFS_WIDTH_LO
  ldd r9, Y+WIN_OFFS_WIDTH_HI
  add r8, r18
  adc r9, r19

  ; calc abs Y pos
  ldd r18, Y+WIN_OFFS_Y_LO
  ldd r19, Y+WIN_OFFS_Y_HI
  add r6, r18                ; add Y of window
  adc r7, r19
  
  ; calc first Y pos behind window
  ldd r10, Y+WIN_OFFS_HEIGHT_LO
  ldd r11, Y+WIN_OFFS_HEIGHT_HI
  add r10, r18
  adc r11, r19
  ret
; @end



; ---------------------------------------------------------------------------
; @routine winDrawChar
;
; @param Y pointer to screen object in SDRAM
; @param  R16     char to write
; @param  R5:R4   absolute X on screen
; @param  R7:R6   absolute Y on screen
; @param  R9:R8   first X pos right of windows
; @return R5:R4   X pos behind char
; @clobbers any, !Y, !R6, !R7

winDrawChar:
  push zl
    push zh
      mov r12, r16
      ldd zl, Y+WIN_OFFS_FONT_LO
      ldd zh, Y+WIN_OFFS_FONT_HI

      ; check whether the char fits inside window
      bigcall FONT_GetCharWidth         ; r16=char width

      clr r17
      add r16, r4                       ; char width+X
      adc r17, r5
      sub r16, r8                       ; check against window width
      sbc r17, r9
      brcc winDrawChar_ret              ; not fit, jmp
    
      ; actually draw char
      mov r16, r12
      push r8
        push r9
          push r10
            push r11
              bigcall Display_DrawChar
            pop r11
          pop r10
        pop r9
      pop r8
      clr r16
      add r4, r18                       ; increment X
      adc r5, r16
      sec                               ; write succeeded
winDrawChar_ret:
    pop zh
  pop zl
  ret
; @end



; ---------------------------------------------------------------------------
; @routine Window_WriteHexWordAt @global
;
; @param Y pointer to screen object in SDRAM
; @param  R17:R16 word to write
; @param  R5:R4   X (dest)
; @param  R7:R6   Y (dest)
; @return R5:R4   X pos behind string
; @clobbers any, !Y

Window_WriteHexWordAt:
  push r16
    mov r16, r17
    rcall Window_WriteHexByteAt
  pop r16
  rcall Window_WriteHexByteAt
  ret
; @end



; ---------------------------------------------------------------------------
; @routine Window_WriteHexByteAt @global
;
; @param Y pointer to screen object in SDRAM
; @param  R16     byte to write
; @param  R5:R4   X (dest)
; @param  R7:R6   Y (dest)
; @return R5:R4   X pos behind string
; @clobbers any, !Y

Window_WriteHexByteAt:
  push r16
    swap r16
    rcall winWriteNibble
  pop r16
  rcall winWriteNibble
  ret
; @end



winWriteNibble:
  push r4
    push r5
      push r6
        push r7
          rcall winNibbleToAscii   ; write high nibble (r16, r17)
          rcall Window_DrawCharAt  ; draw
        pop r7
      pop r6
    pop r5
  pop r4
  clr r17
  add r4, r18
  adc r5, r17
  ret
; @end



; ---------------------------------------------------------------------------
; @routine winNibbleToAscii
;
; Convert a nibble to an ASCII char.
; @return R16 ASCII representation of that nibble (e.g. '0' for 0)
; @param  R16 byte (in bits 0-3)
; @clobbers r16, r17

winNibbleToAscii:
  andi r16, 0xf
  cpi r16, 10
  brcs winNibbleToAscii_l1
  ldi r17, 7
  add r16, r17
winNibbleToAscii_l1:
  ldi r17, '0'
  add r16, r17
  ret
; @end






#if 0
; ---------------------------------------------------------------------------
; @routine Window_DrawTextFlash @global
;
; @param Y pointer to screen object in SDRAM
; @param  R5:R4   X (dest)
; @param  R7:R6   Y (dest)
; @return R5:R4   X pos behind string
; @return R7:R6   Y pos behind string
; @clobbers any, !Y

Window_DrawTextFlash:
  ; calc abs X pos
  ldd r18, Y+WIN_OFFS_X_LO
  ldd r19, Y+WIN_OFFS_X_HI
  add r4, r18                  ; add X of window
  adc r5, r19

  ; calc first X pos behind window
  ldd r8, Y+WIN_OFFS_WIDTH_LO
  ldd r9, Y+WIN_OFFS_WIDTH_HI
  add r8, r18
  adc r9, r19

  ; calc abs Y pos
  ldd r18, Y+WIN_OFFS_Y_LO
  ldd r19, Y+WIN_OFFS_Y_HI
  add r6, r18                ; add Y of window
  adc r7, r19
  
  ; calc first Y pos behind window
  ldd r10, Y+WIN_OFFS_HEIGHT_LO
  ldd r11, Y+WIN_OFFS_HEIGHT_HI
  add r10, r18
  adc r11, r19

Window_DrawTextFlash_loop:
    push zl
      push zh
        rcall winCalcLengthWordFlash
      pop zh
    pop zl
    mov r18, r4
    mov r19, r5
    add r18, r12
    adc r19, r13
    sub r18, r8
    sbc r19, r9
    brcs Window_DrawTextFlash_xOkay
    ; we need to go to the beginning of the next line
    rcall Window_DrawTextFlash_nextLine
    brcc Window_DrawTextFlash_loopEnd ; outside the window, jmp
Window_DrawTextFlash_xOkay:
    rcall winDrawWordFlash            ; Z points at blank/0 byte after call
    lpm r16, Z+
    tst r16                           ; end of string?
    breq Window_DrawTextFlash_loopEnd
    cpi r16, 13
    breq Window_DrawTextFlash_handle13
    ; insert other handled chars here
    ; write blank char
    push zl
      push zh
        ldd zl, Y+WIN_OFFS_FONT_LO
        ldd zh, Y+WIN_OFFS_FONT_HI
        ldi r16, 32                    ; space
        bigcall Display_DrawChar
      pop zh
    pop zl
    add r4, r8   ; increment X
    adc r5, r9


    rjmp Window_DrawTextFlash_loopNext
Window_DrawTextFlash_handle13:
  rcall Window_DrawTextFlash_nextLine
Window_DrawTextFlash_loopNext:
  rjmp Window_DrawTextFlash_loop
Window_DrawTextFlash_nextLine:
  push zl
    push zh
      ldd zl, Y+WIN_OFFS_FONT_LO
      ldd zh, Y+WIN_OFFS_FONT_HI
      bigcall FONT_GetCharWidth     ; r16=char width
    pop zh
  pop zl
  ldd r4, Y+WIN_OFFS_X_LO           ; X=left border
  ldd r5, Y+WIN_OFFS_X_HI
  clr r17
  add r6, r16                       ; increment Y by font height
  adc r7, r17
  mov r16, r6                       ; check against lower border of window
  mov r17, r7
  sub r16, r10
  sbc r17, r11                      ; CF set if inside window, cleared otherwise
  ret
Window_DrawTextFlash_loopEnd:
  ret
; @end




; ---------------------------------------------------------------------------
; @routine winDrawWordFlash
;
; @param Y pointer to screen object in SDRAM
; @param Z pointer to string in FLASH
; @param  R1:R0   background color
; @param  R3:R2   foreground color
; @param  R5:R4   X (dest)
; @param  R7:R6   Y (dest)
; @return r5:r4 next X pos
; @return Z pointer to next char behind current word
; @clobbers any, !Y, !r1-r15

winDrawWordFlash:
winDrawWordFlash_loop:
    lpm r16, Z
    cpi r16, 33
    brcs winDrawWordFlash_ret
    push zl
      push zh
        ldd zl, Y+WIN_OFFS_FONT_LO
        ldd zh, Y+WIN_OFFS_FONT_HI
        bigcall Display_DrawChar
      pop zh
    pop zl
    clr r16
    add r4, r18   ; increment X
    adc r5, r16
    adiw zh:zl, 1
  rjmp winDrawWordFlash_loop
winDrawWordFlash_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine winCalcLengthWordFlash
;
; @param Y pointer to screen object in SDRAM
; @param Z pointer to string in FLASH
; @return r13:r12 width of next word in pixels
; @return Z pointer to next char behind current word
; @clobbers any, !Y, !r1-r11, !r14, !r15

winCalcLengthWordFlash:
  clr r12
  clr r13
winCalcLengthWordFlash_loop:
    lpm r16, Z
    cpi r16, 33
    brcs winCalcLengthWordFlash_ret
    push zl
      push zh
        ldd zl, Y+WIN_OFFS_FONT_LO
        ldd zh, Y+WIN_OFFS_FONT_HI
        bigcall FONT_GetCharWidth     ; r16=char width
        clr r17
        add r12, r16
        adc r13, r17
      pop zh
    pop zl
    brcs winCalcLengthWordFlash_error
    adiw zh:zl, 1                     ; next char
  rjmp winCalcLengthWordFlash_loop
winCalcLengthWordFlash_error:
  ldi r12, 0xff
  ldi r13, 0xff
winCalcLengthWordFlash_ret:
  ret
; @end

#endif ; if 0



#endif ; AQH_AVR_STATICGUI_WINDOW_ASM

