; ***************************************************************************
; copyright   : (C) 2026 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_GUI_TEXTSEL_ASM
#define AQH_AVR_GUI_TEXTSEL_ASM


; ***************************************************************************
; ***************************************************************************




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

.equ TEXTSEL_OFFS_BEGIN        =  HLAYOUT_SIZE
.equ TEXTSEL_OFFS_TEXTLIST_LO  =  TEXTSEL_OFFS_BEGIN+0
.equ TEXTSEL_OFFS_TEXTLIST_HI  =  TEXTSEL_OFFS_BEGIN+1
.equ TEXTSEL_OFFS_CURRIDX      =  TEXTSEL_OFFS_BEGIN+2
.equ TEXTSEL_OFFS_COUNT        =  TEXTSEL_OFFS_BEGIN+3
.equ TEXTSEL_SIZE              =  TEXTSEL_OFFS_BEGIN+4


; selectors
.equ TEXTSEL_SEL_LEFT       = 1
.equ TEXTSEL_SEL_RIGHT      = 2


; child widgets
.equ TEXTSEL_CHILDIDX_LEFT  = 0
.equ TEXTSEL_CHILDIDX_VALUE = 1
.equ TEXTSEL_CHILDIDX_EIGHT = 2


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

.cseg



; ---------------------------------------------------------------------------
; @routine TextSel_new @global
;
; @return CFLAG set of okay, cleared otherwise
; @return Y address of newly created object
; @param  X parent widget
; @param  r16 value for OBJECT_OFFS_OPTS
; @param  r17 value for WIDGET_OFFS_PACK
; @param  r21:r20   pointer to null-terminated list of text ressources in FLASH (byte address for LPM!)
; @clobbers any

TextSel_new:
  ldi r24, LOW(TEXTSEL_SIZE)
  ldi r25, HIGH(TEXTSEL_SIZE)
  push r20
    push r21
      bigcall Object_Alloc           ; (!r16, !r17, !X)
    pop r21
  pop r20
  brcc TextSel_new_ret
  rcall TextSel_Init               ; (any, !Y)
  sec
TextSel_new_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine TextSel_Init @global
;
; @param Y   address of widget
; @param X   parent widget (if any)
; @param r16 value for OBJECT_OFFS_OPTS
; @param r17 value for WIDGET_OFFS_PACK
; @param  r21:r20   pointer to null-terminated list of text ressources in FLASH (byte address for LPM!)
; @clobbers any, !Y

TextSel_Init:
  ; call base class
  push r20
    push r21
      ldi r20, HLAYOUT_MODE_EXPAND
      bigcall HLayout_Init
    pop r21
  pop r20
  brcc TextSel_Init_ret

  ; set values
  std Y+TEXTSEL_OFFS_TEXTLIST_LO, r20
  std Y+TEXTSEL_OFFS_TEXTLIST_HI, r21

  ; set default signal map
  ldi r16, LOW(TextSel_DefaultSignalmap*2)
  std Y+OBJECT_OFFS_SIGNALMAP_LO, r16
  ldi r16, HIGH(TextSel_DefaultSignalmap*2)
  std Y+OBJECT_OFFS_SIGNALMAP_HI, r16

  rcall textSelCreateChildren               ; (any, !Y)
TextSel_Init_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine textSelCreateChildren
;
; @param Y spinner object
; @clobbers any, !Y

textSelCreateChildren:
  push yl
    push yh
      ; create left button
      call textSelCreateLeftButton
      brcc textSelCreateChildren_popRet
      ; create label
      rcall textSelCreateLabel
      brcc textSelCreateChildren_popRet
      ; create right button
      call textSelCreateRightButton
textSelCreateChildren_popRet:
    pop yh
  pop yl
  ret
; @end



; ---------------------------------------------------------------------------
; @routine textSelCreateLeftButton
;
; @param Y object
; @clobbers any, !Y

textSelCreateLeftButton:
  push yl
    push yh
      ; create button
      mov xl, yl
      mov xh, yh
      ldi r16, (1<<WIDGET_OPTS_BORDER_BIT)                                                                ; OPTS
      ldi r17, (WIDGET_PACK_BEGIN<<WIDGET_PACK_HSELF0_BIT) | (WIDGET_PACK_CENTER<<WIDGET_PACK_VSELF0_BIT) ; PACK
      ldi r20, LOW(RESSOURCE_TXT_LESSERTHAN_C)   ; text ressource
      ldi r21, HIGH(RESSOURCE_TXT_LESSERTHAN_C)
      ldi r22, TEXTSEL_SEL_LEFT                  ; selector
      ldi r23, BUTTON_MODE_REPEATED
      bigcall TextButton_new
      brcc textSelCreateLeftButton_done
    
      ; set style in Label part of the text button
      bigcall OBJ_GetFirstChild
      brcc textSelCreateLeftButton_done
      mov yl, r18
      mov yh, r19
      ldi r16, LOW(TextSel_ButtonStyle*2)
      std Y+WIDGET_OFFS_STYLE_LO, r16
      ldi r16, HIGH(TextSel_ButtonStyle*2)
      std Y+WIDGET_OFFS_STYLE_HI, r16
textSelCreateLeftButton_done:
    pop yh
  pop yl
  ret
; @end



; ---------------------------------------------------------------------------
; @routine textSelCreateRightButton
;
; @param Y object
; @clobbers any, !Y

textSelCreateRightButton:
  push yl
    push yh
      ; create button
      mov xl, yl
      mov xh, yh
      ldi r16, (1<<WIDGET_OPTS_BORDER_BIT)                                                                ; OPTS
      ldi r17, (WIDGET_PACK_BEGIN<<WIDGET_PACK_HSELF0_BIT) | (WIDGET_PACK_CENTER<<WIDGET_PACK_VSELF0_BIT) ; PACK
      ldi r20, LOW(RESSOURCE_TXT_GREATERTHAN_C)   ; text ressource
      ldi r21, HIGH(RESSOURCE_TXT_GREATERTHAN_C)
      ldi r22, TEXTSEL_SEL_RIGHT                 ; selector
      ldi r23, BUTTON_MODE_REPEATED
      bigcall TextButton_new
      brcc textSelCreateRightButton_done
    
      ; set style in Label part of the text button
      bigcall OBJ_GetFirstChild
      brcc textSelCreateRightButton_done
      mov yl, r18
      mov yh, r19
      ldi r16, LOW(TextSel_ButtonStyle*2)
      std Y+WIDGET_OFFS_STYLE_LO, r16
      ldi r16, HIGH(TextSel_ButtonStyle*2)
      std Y+WIDGET_OFFS_STYLE_HI, r16
textSelCreateRightButton_done:
    pop yh
  pop yl
  ret
; @end



; ---------------------------------------------------------------------------
; @routine textSelCreateLabel
;
; @param Y object
; @clobbers any, !Y

textSelCreateLabel:
  push yl
    push yh
      ; create label
      clr r16                                 ; begin with first text ressource
      rcall textSelGetRessIdAt
      mov r20, xl
      mov r21, xh
      ldi r16, 0                                                                                           ; OPTS
      ldi r17, (WIDGET_PACK_END<<WIDGET_PACK_HSELF0_BIT) | (WIDGET_PACK_CENTER<<WIDGET_PACK_VSELF0_BIT) | \
               (WIDGET_PACK_END<<WIDGET_PACK_HCONTENT0_BIT) | (WIDGET_PACK_CENTER<<WIDGET_PACK_VCONTENT0_BIT)   ; PACK
      mov xl, yl
      mov xh, yh
      bigcall Label_new
    pop yh
  pop yl
  ret
; @end




; ---------------------------------------------------------------------------
; @routine textSelSetValue
;
; @param Y widget
; @param r16 new value
; @clobbers any, !Y

textSelSetValue:
  ldd r17, Y+TEXTSEL_OFFS_COUNT
  cp r16, r17
  brcc textSelSetValue_ret
  ldd r17, Y+TEXTSEL_OFFS_CURRIDX
  std Y+TEXTSEL_OFFS_CURRIDX, r16
  push r17
    rcall textSelSendValue
  pop r17
  ; only emit signal if changed
  ldd r16, Y+TEXTSEL_OFFS_CURRIDX
  cp r16, r17
  breq textSelSetValue_ret
  rcall textSelEmitCmdSignal
textSelSetValue_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine textSelSendValue
;
; @param Y widget
; @clobbers any, !Y

textSelSendValue:
  ldi r16, TEXTSEL_CHILDIDX_VALUE
  bigcall OBJ_GetChildAt                ; r19:r18=value label (r16)
  brcc textSelSendValue_ret
  push yl
    push yh
      ldd r16, Y+TEXTSEL_OFFS_CURRIDX
      rcall textSelGetRessIdAt          ; X=ressource id (R16, R17)
      mov yl, r18
      mov yh, r19
      ldi r17, LABEL_VALUE_TEXTRES
      bigcall Widget_SetValue           ; (any, !Y)
    pop yh
  pop yl
textSelSendValue_ret:
  ret
; @end




; ---------------------------------------------------------------------------
; @routine textSelEmitCmdSignal
;
; @param Y widget
; @clobbers any, !Y

textSelEmitCmdSignal:
  ldi r16, WIDGET_SIGNAL_COMMAND
  ldd xl, Y+TEXTSEL_OFFS_CURRIDX
  clr xh
  bigjmp OBJ_EmitSignal
; @end



; ---------------------------------------------------------------------------
; @routine textCountRessources
;
; @param Y widget
; @clobbers r16-r19

textCountRessources:
  push zl
    push zh
      ldd zl, Y+TEXTSEL_OFFS_TEXTLIST_LO
      ldd zh, Y+TEXTSEL_OFFS_TEXTLIST_HI
      mov r16, zl
      or r16, zh
      breq textCountRessources_done
      clr r17
textCountRessources_loop:
        lpm r18, Z+
        lpm r19, Z+
        mov r16, r18
        or r16, r19
        breq textCountRessources_done
        inc r17
      rjmp textCountRessources_loop
textCountRessources_done:
    pop zh
  pop zl
  std Y+TEXTSEL_OFFS_COUNT, r17
  ret
; @end



; ---------------------------------------------------------------------------
; @routine textSelGetRessIdAt
;
; @param Y widget
; @param r16 idx
; @return CFLAG set if ressource id found
; @return X ressource id (if CFLAG set, otherwise NULL)
; @clobbers r16, r17

textSelGetRessIdAt:
  push zl
    push zh
      ldd r17, Y+TEXTSEL_OFFS_COUNT
      cp r16, r17
      brcc textSelGetRessIdAt_done
      add r16, r16
      ldd zl, Y+TEXTSEL_OFFS_TEXTLIST_LO
      ldd zh, Y+TEXTSEL_OFFS_TEXTLIST_HI
      mov r17, zl
      or r17, zh
      breq textSelGetRessIdAt_notFound
      add zl, r16
      adc zh, r16
      sub zh, r16
      lpm xl, Z+
      lpm xh, Z
      mov r17, xl
      or r17, xh
      breq textSelGetRessIdAt_notFound
      sec
      rjmp textSelGetRessIdAt_done
textSelGetRessIdAt_notFound:
      clr xl
      clr xh
      clc
textSelGetRessIdAt_done:
    pop zh
  pop zl
  ret
; @end





; ***************************************************************************
; signal handlers


; ---------------------------------------------------------------------------
; @routine TextSel_OnCmdLeft @global
;
; @param Y widget

TextSel_OnCmdLeft:
  ldd r16, Y+TEXTSEL_OFFS_CURRIDX
  tst r16
  breq TextSel_OnCmdLeft_ret
  dec r16
  rcall textSelSetValue
TextSel_OnCmdLeft_ret:
  sec
  ret
; @end



; ---------------------------------------------------------------------------
; @routine TextSel_OnCmdRight @global
;
; @param Y widget

TextSel_OnCmdRight:
  ldd r16, Y+TEXTSEL_OFFS_CURRIDX
  inc r16
  rcall textSelSetValue
TextSel_OnCmdRight_ret:
  sec
  ret
; @end



; ---------------------------------------------------------------------------
; @routine TextSel_OnSetValue @global
;
; @param Y widget
; @param X new value

TextSel_OnSetValue:
  tst xh
  brne TextSel_OnSetValue_ret
  ldd r17, Y+TEXTSEL_OFFS_COUNT
  mov r16, xl
  rcall textSelSendValue
TextSel_OnSetValue_ret:
  sec
  ret
; @end



; ---------------------------------------------------------------------------
; @routine TextSel_OnGetValue @global
;
; @param  Y       widget
; @return r19:r18 value

TextSel_OnGetValue:
  ldd r18, Y+TEXTSEL_OFFS_CURRIDX
  clr r19
  sec
  ret
; @end





; ***************************************************************************
; data in FLASH


TextSel_ButtonStyle:
  .dw DISPLAY_COLOR_BLACK        ; frontCol_norm
  .dw DISPLAY_COLOR_WHITE        ; backCol_norm
  .dw DISPLAY_COLOR_BLACK        ; borderCol_norm
  .dw DISPLAY_COLOR_WHITE        ; shadowCol_norm
  
  .dw DISPLAY_COLOR_WHITE        ; frontCol_activated
  .dw DISPLAY_COLOR_NAVY         ; backCol_activated
  .dw DISPLAY_COLOR_BLACK        ; borderCol_activated
  .dw DISPLAY_COLOR_WHITE        ; shadowCol_activated
  
  .db 6, 0                       ; outerBorderSize, innerBorderSize
  .dw ili9341Font12x16_1*2       ; font
  .db 12, 16                     ; charWidth, charHeight
; @end



TextSel_DefaultSignalmap:
  ; header
  .dw HLayout_DefaultSignalmap*2  ; next table to use
  ; entries

  .db TEXTSEL_SEL_LEFT,          WIDGET_SIGNAL_COMMAND,  LOW(TextSel_OnCmdLeft),     HIGH(TextSel_OnCmdLeft)
  .db TEXTSEL_SEL_RIGHT,         WIDGET_SIGNAL_COMMAND,  LOW(TextSel_OnCmdRight),    HIGH(TextSel_OnCmdRight)
  .db WIDGET_VALUE_CURRENTVALUE, WIDGET_SIGNAL_SETVALUE, LOW(TextSel_OnSetValue),    HIGH(TextSel_OnSetValue)
  .db WIDGET_VALUE_CURRENTVALUE, WIDGET_SIGNAL_GETVALUE, LOW(TextSel_OnGetValue),    HIGH(TextSel_OnGetValue)
  .db 0, 0, 0, 0  ; end of table



#endif

