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


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


; CWIDGET dialog configuration
.equ CWIDGETCFG_MAINWIDGET_TYPE_HLAYOUT = 1
.equ CWIDGETCFG_MAINWIDGET_TYPE_VLAYOUT = 2
.equ CWIDGETCFG_MAINWIDGET_TYPE_MLAYOUT = 3
.equ CWIDGETCFG_MAINWIDGET_TYPE_NEXT    = 4

.equ CWIDGETCFG_WIDGET_TYPE_LABEL       = 1
.equ CWIDGETCFG_WIDGET_TYPE_VALUELABEL  = 2
.equ CWIDGETCFG_WIDGET_TYPE_IMAGEVIEW   = 3
.equ CWIDGETCFG_WIDGET_TYPE_HSPINNER    = 4
.equ CWIDGETCFG_WIDGET_TYPE_TEXTBUTTON  = 5
.equ CWIDGETCFG_WIDGET_TYPE_IMAGEBUTTON = 6
.equ CWIDGETCFG_WIDGET_TYPE_TEXTSEL     = 7
.equ CWIDGETCFG_WIDGET_TYPE_NEXT        = 8

.equ CWIDGETCFG_WIDGET_FLAGS_MINMAXVALUES_BIT = 0

.equ CWIDGETCFG_OFFS_HEADER_TYPE               = 0 ; HLAYOUT, VLAYOUT, MLAYOUT
.equ CWIDGETCFG_OFFS_HEADER_FLAGS              = 1
.equ CWIDGETCFG_OFFS_HEADER_STYLE_LO           = 2
.equ CWIDGETCFG_OFFS_HEADER_STYLE_HI           = 3
.equ CWIDGETCFG_OFFS_HEADER_PARAM1             = 4 ; R20
.equ CWIDGETCFG_OFFS_HEADER_PARAM2             = 5 ; R21
.equ CWIDGETCFG_HEADER_SIZE                    = 6

.equ CWIDGETCFG_OFFS_WIDGET_TYPE        = 0  ; 0=end
.equ CWIDGETCFG_OFFS_WIDGET_FLAGS       = 1
.equ CWIDGETCFG_OFFS_WIDGET_SELECTOR    = 2
.equ CWIDGETCFG_OFFS_WIDGET_RESERVED    = 3
.equ CWIDGETCFG_OFFS_WIDGET_OPTS        = 4
.equ CWIDGETCFG_OFFS_WIDGET_PACK        = 5
.equ CWIDGETCFG_OFFS_WIDGET_STYLE_LO    = 6
.equ CWIDGETCFG_OFFS_WIDGET_STYLE_HI    = 7
.equ CWIDGETCFG_OFFS_WIDGET_PARAM1      = 8  ; R20
.equ CWIDGETCFG_OFFS_WIDGET_PARAM2      = 9  ; R21
.equ CWIDGETCFG_OFFS_WIDGET_PARAM3      = 10  ; R22
.equ CWIDGETCFG_OFFS_WIDGET_PARAM4      = 11  ; R23
.equ CWIDGETCFG_OFFS_WIDGET_MINVALUE_LO = 12
.equ CWIDGETCFG_OFFS_WIDGET_MINVALUE_HI = 13
.equ CWIDGETCFG_OFFS_WIDGET_MAXVALUE_LO = 14
.equ CWIDGETCFG_OFFS_WIDGET_MAXVALUE_HI = 15
.equ CWIDGETCFG_WIDGET_SIZE             = 16



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

.cseg



; ---------------------------------------------------------------------------
; @routine CWidget_Create
;
; @param Y      pointer to target object for signals emitted by child widgets
; @param X      pointer to window to become parent for the new widget
; @param Z      pointer to dialog configuration
; @param r16    value for OBJECT_OFFS_OPTS
; @param r17    value for WIDGET_OFFS_PACK
; @return CFLAG set of okay, cleared otherwise

CWidget_Create:
  push yl    ; target
    push yh
      rcall cWidgetMkMainWidget
      mov xl, yl                 ; layout widget
      mov xh, yh
    pop yh                       ; target
  pop yl
  brcc CWidget_Create_ret

  adiw zh:zl, CWIDGETCFG_HEADER_SIZE ; go to first child widget
  rcall CWidget_CreateChildWidgets
CWidget_Create_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine CWidget_CreateChildWidgets @global
;
; @param Y      pointer to target window for signals emitted by created widgets
; @param X      pointer to window to become parent to created widgets
; @param Z      pointer to dialog configuration (ptr to first widget, not to header!)
; @return CFLAG set of okay, cleared otherwise
; @clobbers any, !X, !Y

CWidget_CreateChildWidgets:
CWidget_CreateChildWidgets_loop:
    lpm r16, Z
    tst r16
    breq CWidget_CreateChildWidgets_done
    push yl
      push yh
        push xl
          push xh
            rcall cWidgetMkChildWidget
          pop xh
        pop xl
      pop yh
    pop yl
    brcc CWidget_CreateChildWidgets_ret
    adiw zh:zl, CWIDGETCFG_WIDGET_SIZE
  rjmp CWidget_CreateChildWidgets_loop
CWidget_CreateChildWidgets_done:
  sec
CWidget_CreateChildWidgets_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine cWidgetMkMainWidget
;
; @param Y      pointer to main window
; @param X      pointer to content window of MainWindow (is a VLayout, becomes parent)
; @param Z      pointer to dialog configuration
; @param r16    value for OBJECT_OFFS_OPTS
; @param r17    value for WIDGET_OFFS_PACK
; @return CFLAG set of okay, cleared otherwise
; @return Y     pointer to created content widget
; @clobbers any, !Z

cWidgetMkMainWidget:
  lpm r18, Z
  cpi r18, CWIDGETCFG_MAINWIDGET_TYPE_NEXT
  brcc cWidgetMkMainWidget_ret
  dec r18

  ; determine location in calltable
  clr r19
  ldi r20, LOW(cWidgetMkMainWidget_table)
  ldi r21, HIGH(cWidgetMkMainWidget_table)
  add r18, r20
  adc r19, r21

  ; prepare params
  adiw zh:zl, CWIDGETCFG_OFFS_HEADER_PARAM1
  lpm r20, Z+
  lpm r21, Z
  sbiw zh:zl, (CWIDGETCFG_OFFS_HEADER_PARAM1+1)

  push zl
    push zh
      rcall cWidgetMkMainWidget_callTable
    pop zh
  pop zl
  brcc cWidgetMkMainWidget_ret
  
  ; set style (if any)
  adiw zh:zl, CWIDGETCFG_OFFS_HEADER_STYLE_LO
  lpm xl, Z+
  lpm xh, Z
  sbiw zh:zl, (CWIDGETCFG_OFFS_HEADER_STYLE_LO+1)
  mov r18, xl
  or r18, xh
  sec
  breq cWidgetMkMainWidget_ret
  push zl
    push zh
      bigcall Widget_SetStyle
    pop zh
  pop zl
cWidgetMkMainWidget_ret:
  ret
cWidgetMkMainWidget_callTable:
  push r18      ; indirect jump
  push r19
  ret
cWidgetMkMainWidget_table:
  rjmp cWidgetMkMainWidget_hlayout
  rjmp cWidgetMkMainWidget_vlayout
  rjmp cWidgetMkMainWidget_mlayout
cWidgetMkMainWidget_hlayout:
  bigjmp HLayout_new
cWidgetMkMainWidget_vlayout:
  bigjmp VLayout_new
cWidgetMkMainWidget_mlayout:
  bigjmp MCLayout_new
; @end



; ---------------------------------------------------------------------------
; @routine cWidgetMkChildWidget
; @param Y      pointer to main window
; @param X      pointer to parent window
; @param Z      pointer to current widget configuration
; @return CFLAG set of okay, cleared otherwise
; @return Y     pointer to created widget
; @clobbers any, !Z

cWidgetMkChildWidget:
  lpm r16, Z
  cpi r16, CWIDGETCFG_WIDGET_TYPE_NEXT
  brcs cWidgetMkChildWidget_typeOk
  rjmp cWidgetMkChildWidget_ret
cWidgetMkChildWidget_typeOk:
  dec r16
  ; prepare params
  adiw zh:zl, CWIDGETCFG_OFFS_WIDGET_PARAM1
  lpm r20, Z+
  lpm r21, Z+
  lpm r22, Z+
  lpm r23, Z
  sbiw zh:zl, (CWIDGETCFG_OFFS_WIDGET_PARAM1+3)

  ; determine position within jumptable
  clr r17
  ldi r18, LOW(cWidgetMkChildWidget_table)
  ldi r19, HIGH(cWidgetMkChildWidget_table)
  add r18, r16
  adc r19, r17

  ; prepare opts and pack mode
  adiw zh:zl, CWIDGETCFG_OFFS_WIDGET_OPTS
  lpm r16, Z+
  lpm r17, Z
  sbiw zh:zl, (CWIDGETCFG_OFFS_WIDGET_OPTS+1)

  ; call table routine
  push zl
    push zh
      push yl
        push yh
          rcall cWidgetMkChildWidget_callTable
        pop r21   ; pop Y into r21:r20
      pop r20
    pop zh
  pop zl
  brcc cWidgetMkChildWidget_ret
  
  ; set target and selector
  adiw zh:zl, CWIDGETCFG_OFFS_WIDGET_SELECTOR
  lpm r16, Z
  sbiw zh:zl, CWIDGETCFG_OFFS_WIDGET_SELECTOR
  std Y+OBJECT_OFFS_SELECTOR, r16
  std Y+OBJECT_OFFS_TARGET_LO, r20
  std Y+OBJECT_OFFS_TARGET_HI, r21
  
  ; set style (if any)
  adiw zh:zl, CWIDGETCFG_OFFS_WIDGET_STYLE_LO
  lpm xl, Z+
  lpm xh, Z
  sbiw zh:zl, (CWIDGETCFG_OFFS_WIDGET_STYLE_LO+1)
  mov r18, xl
  or r18, xh
  breq cWidgetMkChildWidget_setminmax
  push zl
    push zh
      bigcall Widget_SetStyle
    pop zh
  pop zl
cWidgetMkChildWidget_setminmax:
  adiw zh:zl, CWIDGETCFG_OFFS_WIDGET_FLAGS
  lpm r16, Z
  sbiw zh:zl, CWIDGETCFG_OFFS_WIDGET_FLAGS
  sbrs r16, CWIDGETCFG_WIDGET_FLAGS_MINMAXVALUES_BIT      ; only set min/max if flag set
    rjmp cWidgetMkChildWidget_done
  adiw zh:zl, CWIDGETCFG_OFFS_WIDGET_MINVALUE_LO
  lpm xl, Z+
  lpm xh, Z
  sbiw zh:zl, (CWIDGETCFG_OFFS_WIDGET_MINVALUE_LO+1)
  push zl
    push zh
      bigcall Widget_SetMinValue
    pop zh
  pop zl

  adiw zh:zl, CWIDGETCFG_OFFS_WIDGET_MAXVALUE_LO
  lpm xl, Z+
  lpm xh, Z
  sbiw zh:zl, (CWIDGETCFG_OFFS_WIDGET_MAXVALUE_LO+1)
  push zl
    push zh
      bigcall Widget_SetMaxValue
    pop zh
  pop zl
cWidgetMkChildWidget_done:
  sec
cWidgetMkChildWidget_ret:
  ret
cWidgetMkChildWidget_callTable:
  push r18      ; indirect jump
  push r19
  ret
cWidgetMkChildWidget_table:
  rjmp cWidgetMkChildWidget_label
  rjmp cWidgetMkChildWidget_vlabel
  rjmp cWidgetMkChildWidget_imageview
  rjmp cWidgetMkChildWidget_hspinner
  rjmp cWidgetMkChildWidget_textbutton
  rjmp cWidgetMkChildWidget_imagebutton
  rjmp cWidgetMkChildWidget_textsel

cWidgetMkChildWidget_label:
  bigjmp Label_new
cWidgetMkChildWidget_vlabel:
  bigjmp ValueLabel_new
cWidgetMkChildWidget_imageview:
  bigjmp ImageView_new
cWidgetMkChildWidget_hspinner:
  bigjmp HSpinner_new
cWidgetMkChildWidget_textbutton:
  bigjmp TextButton_new
cWidgetMkChildWidget_imagebutton:
  bigjmp ImageButton_new
cWidgetMkChildWidget_textsel:
  bigjmp TextSel_new
; @end





#endif

